Skip to content

Commit 285bacc

Browse files
committed
Merge branch 'master' of github.com:rasmusjp/umbraco-graphql into package-ui
2 parents 22b9d3f + 9369b82 commit 285bacc

17 files changed

+2876
-27
lines changed

.gitignore

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@
66
*.bak
77
*.orig
88
*.zip
9-
109
.vs/
1110
.idea/
12-
1311
/build/
1412
/packages/
1513
/artifacts/
1614
bower_components/
1715
node_modules/
18-
1916
[Bb]in/
20-
[Oo]bj/
17+
[Oo]bj/
18+
CurrentSettings.vssettings
19+
Visual Studio 2017/*

Our.Umbraco.GraphQL.sln

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ EndProject
88
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Website", "samples\Website\Website.csproj", "{C2001952-0774-4BFA-AF30-043B3B16D275}"
99
EndProject
1010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{BE019E17-BF39-443C-8D62-74940D3B6560}"
11+
ProjectSection(SolutionItems) = preProject
12+
samples\Website\Web.config.template = samples\Website\Web.config.template
13+
EndProjectSection
1114
EndProject
1215
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Our.Umbraco.GraphQL", "src\Our.Umbraco.GraphQL\Our.Umbraco.GraphQL.csproj", "{59294783-3A17-479B-90C5-A3A2967176DE}"
1316
EndProject
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using Newtonsoft.Json;
2+
using Our.Umbraco.GraphQL.Models;
3+
using Our.Umbraco.GraphQL.Models.ApiModels;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Net.Http;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using System.Web.Mvc;
11+
using Umbraco.Core;
12+
using Umbraco.Core.Persistence;
13+
using Umbraco.Web.WebApi;
14+
15+
namespace Our.Umbraco.GraphQL.Controllers
16+
{
17+
public class GraphQLPermissionsController : UmbracoAuthorizedApiController
18+
{
19+
private readonly UmbracoDatabase _database = ApplicationContext.Current.DatabaseContext.Database;
20+
21+
// TODO: Lock down the ability to set/view permissions to a User Group
22+
23+
/// <summary>
24+
/// Sets the GraphQL permisisons for what fields are accessible for the specified account
25+
/// </summary>
26+
/// <param name="accountPermissions">The set permissions request</param>
27+
/// <remarks>
28+
/// Default endpoint for the request: /umbraco/backoffice/api/GraphQLPermissions/SetPermissions
29+
/// </remarks>
30+
[HttpPost]
31+
public void SetPermissions(SetAccountPermissionsRequest accountPermissions)
32+
{
33+
var entries = new List<AccountSettings>();
34+
foreach (var permission in accountPermissions.Permissions)
35+
{
36+
var accountSettingEntry = new AccountSettings();
37+
// Always default to empty for niw
38+
accountSettingEntry.Notes = "";
39+
// Default to read until we have functionality for other permissions
40+
accountSettingEntry.Permission = Permissions.Read; // TODO: functionality for Write permissions
41+
accountSettingEntry.AccountId = accountPermissions.AccountId;
42+
accountSettingEntry.PropertyTypeAlias = permission.PropertyAlias;
43+
accountSettingEntry.DocTypeAlias = permission.DoctypeAlias;
44+
accountSettingEntry.IsBuiltInProperty = permission.IsBuiltInProperty;
45+
accountSettingEntry.CreatedOn = DateTime.UtcNow;
46+
accountSettingEntry.UpdatedOn = DateTime.UtcNow;
47+
48+
entries.Add(accountSettingEntry);
49+
}
50+
51+
// Clear existing settings
52+
var sql = new Sql("DELETE FROM GraphQL_AccountSettings WHERE AccountId=@0", accountPermissions.AccountId);
53+
_database.Execute(sql);
54+
55+
// Insert in bulk so it's handled within a single query
56+
_database.BulkInsertRecords(entries, ApplicationContext.Current.DatabaseContext.SqlSyntax);
57+
}
58+
59+
/// <summary>
60+
/// Gets a list of the current GraphQL permissions for the specified account
61+
/// </summary>
62+
/// <param name="accountId">The GraphQL account id</param>
63+
/// <returns>
64+
/// Example request endpoint: /umbraco/backoffice/api/GraphQLPermissions/GetPermissions?accountId=1
65+
/// </returns>
66+
[HttpGet]
67+
public string GetPermissions(int accountId)
68+
{
69+
var sql = new Sql("SELECT * FROM GraphQL_AccountSettings WHERE AccountId=@0", accountId);
70+
var settings = _database.Query<AccountSettings>(sql);
71+
72+
if (settings != null)
73+
{
74+
var accountPermissions = new List<AccountPermission>();
75+
foreach (var permission in settings)
76+
{
77+
var accountPermission = new AccountPermission();
78+
accountPermission.Notes = permission.Notes;
79+
accountPermission.Permission = permission.Permission.ToString();
80+
accountPermission.PropertyAlias = permission.PropertyTypeAlias;
81+
accountPermission.DoctypeAlias = permission.DocTypeAlias;
82+
accountPermission.IsBuiltInProperty = permission.IsBuiltInProperty;
83+
84+
accountPermissions.Add(accountPermission);
85+
}
86+
87+
var results = JsonConvert.SerializeObject(accountPermissions);
88+
return results;
89+
}
90+
91+
return null;
92+
}
93+
}
94+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using Semver;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Web;
6+
using Umbraco.Core;
7+
using Umbraco.Core.Logging;
8+
using Umbraco.Core.Persistence.Migrations;
9+
10+
namespace Our.Umbraco.GraphQL.Events
11+
{
12+
/// <summary>
13+
/// Runs our DB Migrations on startup.
14+
///
15+
/// Thank you to the wonderful Kevin Jump for pointers on how to get this as slick as it is
16+
/// See: https://github.com/KevinJump/UmbracoMigrationsDemo for details
17+
/// </summary>
18+
public class MigrationEventHandler : ApplicationEventHandler
19+
{
20+
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
21+
{
22+
// Update the version number as we deploy new DB changes to run any new Migrations
23+
ApplyMigrations(applicationContext, "GraphQL", new SemVersion(1, 0, 0));
24+
}
25+
26+
private void ApplyMigrations(ApplicationContext applicationContext, string productName, SemVersion targetVersion)
27+
{
28+
var currentVersion = new SemVersion(0);
29+
30+
var migrations = applicationContext.Services.MigrationEntryService.GetAll(productName);
31+
var latest = migrations.OrderByDescending(x => x.Version).FirstOrDefault();
32+
if (latest != null)
33+
currentVersion = latest.Version;
34+
35+
if (targetVersion == currentVersion)
36+
return;
37+
38+
var migrationRunner = new MigrationRunner(
39+
applicationContext.Services.MigrationEntryService,
40+
applicationContext.ProfilingLogger.Logger,
41+
currentVersion,
42+
targetVersion,
43+
productName);
44+
45+
try
46+
{
47+
migrationRunner.Execute(applicationContext.DatabaseContext.Database);
48+
}
49+
catch (Exception ex)
50+
{
51+
applicationContext.ProfilingLogger
52+
.Logger.Error<MigrationEventHandler>("Error running " + productName + " Migration", ex);
53+
}
54+
}
55+
}
56+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using GraphQL;
2+
using GraphQL.Builders;
3+
using GraphQL.Types;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace Our.Umbraco.GraphQL
11+
{
12+
// Based on the example used here https://graphql-dotnet.github.io/docs/getting-started/authorization
13+
public static class GraphQLAuthenticationExtensions
14+
{
15+
public static readonly string PermissionsKey = "permissions";
16+
17+
/// <summary>
18+
/// Checks if this field has any permissions set or not, if not then anyone can view it
19+
/// </summary>
20+
/// <param name="type"></param>
21+
/// <returns></returns>
22+
public static bool RequiresPermissions(this IProvideMetadata type)
23+
{
24+
var permissions = type.GetMetadata<IEnumerable<string>>(PermissionsKey, new List<string>());
25+
return permissions.Any();
26+
}
27+
28+
public static bool HasPermission(this IProvideMetadata type, string docTypeAlias, IEnumerable<string> claims)
29+
{
30+
var permissionsData = type.GetMetadata<IEnumerable<string>>(PermissionsKey, new List<string>());
31+
var permissions = new List<string>();
32+
33+
foreach (var permissionKey in permissionsData)
34+
{
35+
var permission = permissionKey;
36+
37+
// if it starts with : we don't know what doctype it belongs to on the point of creating the field metadat
38+
// So we work it out when required and pass it in here
39+
if (permissionKey.StartsWith(":"))
40+
{
41+
permission = $"{docTypeAlias}{permissionKey}";
42+
}
43+
44+
permissions.Add(permission);
45+
}
46+
47+
return permissions.All(x => claims?.Contains(x) ?? false);
48+
}
49+
50+
public static bool HasPermission(this IProvideMetadata type, IEnumerable<string> claims)
51+
{
52+
var permissions = type.GetMetadata<IEnumerable<string>>(PermissionsKey, new List<string>());
53+
return permissions.All(x => claims?.Contains(x) ?? false);
54+
}
55+
56+
public static void RequirePermission(this IProvideMetadata type, string permission)
57+
{
58+
var permissions = type.GetMetadata<List<string>>(PermissionsKey);
59+
60+
if (permissions == null)
61+
{
62+
permissions = new List<string>();
63+
type.Metadata[PermissionsKey] = permissions;
64+
}
65+
66+
permissions.Add(permission);
67+
}
68+
69+
public static void SetPermissions(this FieldType type, string documentTypeAlias, bool isBuiltInProperty = false)
70+
{
71+
var propertyAlias = type.Name;
72+
73+
// If its a built in Umbraco property, add an additional flag to the key so it doesn't clash with any custom properties we set
74+
var readPermissionKey = isBuiltInProperty ?
75+
$"{documentTypeAlias}:builtInProperty:{propertyAlias}:Read" : $"{documentTypeAlias}:{propertyAlias}:Read";
76+
77+
type.RequirePermission(readPermissionKey);
78+
}
79+
80+
public static void SetPermissions(this FieldType type, GraphType graphType, bool isBuiltInProperty = false)
81+
{
82+
// The graph type should have the doc type alias set in the meta data so we're accessing it from that
83+
var doctypeAlias = graphType.GetMetadata<string>("documentTypeAlias");
84+
type.SetPermissions(doctypeAlias, isBuiltInProperty);
85+
}
86+
87+
public static void SetDoctypeMetadata(this FieldType type, string doctypeAlias)
88+
{
89+
var currentAlias = type.GetMetadata<List<string>>("documentTypeAlias");
90+
91+
if (currentAlias == null)
92+
{
93+
type.Metadata["documentTypeAlias"] = doctypeAlias;
94+
}
95+
}
96+
97+
public static FieldBuilder<TSourceType, TReturnType> RequirePermission<TSourceType, TReturnType>(
98+
this FieldBuilder<TSourceType, TReturnType> builder, string permission)
99+
{
100+
builder.FieldType.RequirePermission(permission);
101+
return builder;
102+
}
103+
}
104+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using Our.Umbraco.GraphQL.Models;
2+
using System.Linq;
3+
using Umbraco.Core;
4+
using Umbraco.Core.Logging;
5+
using Umbraco.Core.Persistence.Migrations;
6+
using Umbraco.Core.Persistence.SqlSyntax;
7+
using System;
8+
using Umbraco.Core.Persistence;
9+
10+
namespace Our.Umbraco.GraphQL.Migrations
11+
{
12+
[Migration("1.0.0", 1, "GraphQL")]
13+
public class CreateInitialTables : MigrationBase
14+
{
15+
public const string accountsTableName = "Accounts";
16+
public const string accountSettingsTableName = "AccountSettings";
17+
18+
private readonly UmbracoDatabase _database = ApplicationContext.Current.DatabaseContext.Database;
19+
private readonly DatabaseSchemaHelper _schemaHelper;
20+
21+
public CreateInitialTables(ISqlSyntaxProvider sqlSyntax, ILogger logger)
22+
: base(sqlSyntax, logger)
23+
{
24+
_schemaHelper = new DatabaseSchemaHelper(_database, logger, sqlSyntax);
25+
}
26+
27+
public override void Down()
28+
{
29+
Logger.Info<CreateInitialTables>("1.0.0: Running Migration Down");
30+
31+
DropTables();
32+
}
33+
34+
public override void Up()
35+
{
36+
Logger.Info<CreateInitialTables>("1.0.0: Running Migration Up");
37+
38+
CreateTables();
39+
InsertData();
40+
}
41+
42+
private void CreateTables()
43+
{
44+
if (!_schemaHelper.TableExist(accountsTableName))
45+
{
46+
Logger.Info<CreateInitialTables>("Creation Accounts Table");
47+
_schemaHelper.CreateTable<Account>();
48+
}
49+
50+
if (!_schemaHelper.TableExist(accountSettingsTableName))
51+
{
52+
Logger.Info<CreateInitialTables>("Creating AccountSettings Table");
53+
_schemaHelper.CreateTable<AccountSettings>();
54+
}
55+
}
56+
57+
private void DropTables()
58+
{
59+
if (_schemaHelper.TableExist(accountsTableName))
60+
{
61+
Logger.Info<CreateInitialTables>("Deleting Accounts Table");
62+
_schemaHelper.DropTable(accountsTableName);
63+
}
64+
if (_schemaHelper.TableExist(accountSettingsTableName))
65+
{
66+
Logger.Info<CreateInitialTables>("Deleting AccountSettings Table");
67+
_schemaHelper.DropTable(accountSettingsTableName);
68+
}
69+
}
70+
71+
private void InsertData()
72+
{
73+
var account = new Account()
74+
{
75+
//AccessToken = Guid.NewGuid(),
76+
AccessToken = new Guid("6bd10bc4-1d31-478a-8abc-78560086286b"),
77+
CreatedBy = 0,
78+
CreatedOn = DateTime.Now,
79+
UpdatedOn = DateTime.Now,
80+
IsEnabled = true,
81+
Name = "Pete Test",
82+
Notes = "Just as test account setup in the create initial tables migration",
83+
};
84+
85+
_database.Insert(account);
86+
87+
var accountSetting = new AccountSettings()
88+
{
89+
AccountId = account.Id,
90+
DocTypeAlias = "home",
91+
PropertyTypeAlias = "sitename",
92+
IsBuiltInProperty = false,
93+
Permission = Permissions.Read,
94+
CreatedOn = DateTime.Now,
95+
UpdatedOn = DateTime.Now,
96+
Notes = ""
97+
};
98+
99+
_database.Insert(accountSetting);
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)