Port 7.7 - WIP
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
@@ -18,7 +23,76 @@ namespace Umbraco.Core.Models
|
||||
public static bool IsAdmin(this IUser user)
|
||||
{
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
return user.UserType.Alias == "admin";
|
||||
return user.Groups != null && user.Groups.Any(x => x.Alias == Constants.Security.AdminGroupAlias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to lookup the user's gravatar to see if the endpoint can be reached, if so it returns the valid URL
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="userService"></param>
|
||||
/// <param name="staticCache"></param>
|
||||
/// <returns>
|
||||
/// A list of 5 different sized avatar URLs
|
||||
/// </returns>
|
||||
internal static string[] GetCurrentUserAvatarUrls(this IUser user, IUserService userService, ICacheProvider staticCache)
|
||||
{
|
||||
//check if the user has explicitly removed all avatars including a gravatar, this will be possible and the value will be "none"
|
||||
if (user.Avatar == "none")
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
if (user.Avatar.IsNullOrWhiteSpace())
|
||||
{
|
||||
var gravatarHash = user.Email.ToMd5();
|
||||
var gravatarUrl = "https://www.gravatar.com/avatar/" + gravatarHash + "?d=404";
|
||||
|
||||
//try gravatar
|
||||
var gravatarAccess = staticCache.GetCacheItem<bool>("UserAvatar" + user.Id, () =>
|
||||
{
|
||||
// Test if we can reach this URL, will fail when there's network or firewall errors
|
||||
var request = (HttpWebRequest)WebRequest.Create(gravatarUrl);
|
||||
// Require response within 10 seconds
|
||||
request.Timeout = 10000;
|
||||
try
|
||||
{
|
||||
using ((HttpWebResponse)request.GetResponse()) { }
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// There was an HTTP or other error, return an null instead
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (gravatarAccess)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
gravatarUrl + "&s=30",
|
||||
gravatarUrl + "&s=60",
|
||||
gravatarUrl + "&s=90",
|
||||
gravatarUrl + "&s=150",
|
||||
gravatarUrl + "&s=300"
|
||||
};
|
||||
}
|
||||
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
//use the custom avatar
|
||||
var avatarUrl = FileSystemProviderManager.Current.MediaFileSystem.GetUrl(user.Avatar);
|
||||
return new[]
|
||||
{
|
||||
avatarUrl + "?width=30&height=30&mode=crop",
|
||||
avatarUrl + "?width=60&height=60&mode=crop",
|
||||
avatarUrl + "?width=90&height=90&mode=crop",
|
||||
avatarUrl + "?width=150&height=150&mode=crop",
|
||||
avatarUrl + "?width=300&height=300&mode=crop"
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public static void ClearAllowedSections(this IUser user)
|
||||
@@ -61,47 +135,183 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the user has access to the content item based on their start noe
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool HasPathAccess(this IUser user, IContent content)
|
||||
internal static bool HasContentRootAccess(this IUser user, IEntityService entityService)
|
||||
{
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
return HasPathAccess(content.Path, user.StartContentId, Constants.System.RecycleBinContent);
|
||||
return HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
|
||||
}
|
||||
|
||||
internal static bool HasPathAccess(string path, int startNodeId, int recycleBinId)
|
||||
internal static bool HasContentBinAccess(this IUser user, IEntityService entityService)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullOrEmptyException(nameof(path));
|
||||
return HasPathAccess(Constants.System.RecycleBinContent.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
|
||||
}
|
||||
|
||||
internal static bool HasMediaRootAccess(this IUser user, IEntityService entityService)
|
||||
{
|
||||
return HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
|
||||
}
|
||||
|
||||
internal static bool HasMediaBinAccess(this IUser user, IEntityService entityService)
|
||||
{
|
||||
return HasPathAccess(Constants.System.RecycleBinMedia.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
|
||||
}
|
||||
|
||||
internal static bool HasPathAccess(this IUser user, IContent content, IEntityService entityService)
|
||||
{
|
||||
return HasPathAccess(content.Path, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
|
||||
}
|
||||
|
||||
internal static bool HasPathAccess(this IUser user, IMedia media, IEntityService entityService)
|
||||
{
|
||||
return HasPathAccess(media.Path, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
|
||||
}
|
||||
|
||||
internal static bool HasPathAccess(string path, int[] startNodeIds, int recycleBinId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(path));
|
||||
|
||||
// check for no access
|
||||
if (startNodeIds.Length == 0)
|
||||
return false;
|
||||
|
||||
// check for root access
|
||||
if (startNodeIds.Contains(Constants.System.Root))
|
||||
return true;
|
||||
|
||||
var formattedPath = "," + path + ",";
|
||||
var formattedStartNodeId = "," + startNodeId.ToInvariantString() + ",";
|
||||
var formattedRecycleBinId = "," + recycleBinId.ToInvariantString() + ",";
|
||||
|
||||
//only users with root access have access to the recycle bin
|
||||
if (formattedPath.Contains(formattedRecycleBinId))
|
||||
// only users with root access have access to the recycle bin,
|
||||
// if the above check didn't pass then access is denied
|
||||
if (formattedPath.Contains("," + recycleBinId + ","))
|
||||
return false;
|
||||
|
||||
// check for a start node in the path
|
||||
return startNodeIds.Any(x => formattedPath.Contains("," + x + ","));
|
||||
}
|
||||
|
||||
// calc. start nodes, combining groups' and user's, and excluding what's in the bin
|
||||
public static int[] CalculateContentStartNodeIds(this IUser user, IEntityService entityService)
|
||||
{
|
||||
const string cacheKey = "AllContentStartNodes";
|
||||
//try to look them up from cache so we don't recalculate
|
||||
var valuesInUserCache = FromUserCache(user, cacheKey);
|
||||
if (valuesInUserCache != null) return valuesInUserCache;
|
||||
|
||||
var gsn = user.Groups.Where(x => x.StartContentId.HasValue).Select(x => x.StartContentId.Value).Distinct().ToArray();
|
||||
var usn = user.StartContentIds;
|
||||
var vals = CombineStartNodes(UmbracoObjectTypes.Document, gsn, usn, entityService);
|
||||
ToUserCache(user, cacheKey, vals);
|
||||
return vals;
|
||||
}
|
||||
|
||||
// calc. start nodes, combining groups' and user's, and excluding what's in the bin
|
||||
public static int[] CalculateMediaStartNodeIds(this IUser user, IEntityService entityService)
|
||||
{
|
||||
const string cacheKey = "AllMediaStartNodes";
|
||||
//try to look them up from cache so we don't recalculate
|
||||
var valuesInUserCache = FromUserCache(user, cacheKey);
|
||||
if (valuesInUserCache != null) return valuesInUserCache;
|
||||
|
||||
var gsn = user.Groups.Where(x => x.StartMediaId.HasValue).Select(x => x.StartMediaId.Value).Distinct().ToArray();
|
||||
var usn = user.StartMediaIds;
|
||||
var vals = CombineStartNodes(UmbracoObjectTypes.Media, gsn, usn, entityService);
|
||||
ToUserCache(user, cacheKey, vals);
|
||||
return vals;
|
||||
}
|
||||
|
||||
private static int[] FromUserCache(IUser user, string cacheKey)
|
||||
{
|
||||
var entityUser = user as User;
|
||||
if (entityUser == null) return null;
|
||||
|
||||
lock (entityUser.AdditionalDataLock)
|
||||
{
|
||||
return startNodeId == Constants.System.Root;
|
||||
object allContentStartNodes;
|
||||
return entityUser.AdditionalData.TryGetValue(cacheKey, out allContentStartNodes)
|
||||
? allContentStartNodes as int[]
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ToUserCache(IUser user, string cacheKey, int[] vals)
|
||||
{
|
||||
var entityUser = user as User;
|
||||
if (entityUser == null) return;
|
||||
|
||||
lock (entityUser.AdditionalDataLock)
|
||||
{
|
||||
entityUser.AdditionalData[cacheKey] = vals;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool StartsWithPath(string test, string path)
|
||||
{
|
||||
return test.StartsWith(path) && test.Length > path.Length && test[path.Length] == ',';
|
||||
}
|
||||
|
||||
private static string GetBinPath(UmbracoObjectTypes objectType)
|
||||
{
|
||||
var binPath = Constants.System.Root + ",";
|
||||
switch (objectType)
|
||||
{
|
||||
case UmbracoObjectTypes.Document:
|
||||
binPath += Constants.System.RecycleBinContent;
|
||||
break;
|
||||
case UmbracoObjectTypes.Media:
|
||||
binPath += Constants.System.RecycleBinMedia;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("objectType");
|
||||
}
|
||||
return binPath;
|
||||
}
|
||||
|
||||
internal static int[] CombineStartNodes(UmbracoObjectTypes objectType, int[] groupSn, int[] userSn, IEntityService entityService)
|
||||
{
|
||||
// assume groupSn and userSn each don't contain duplicates
|
||||
|
||||
var asn = groupSn.Concat(userSn).Distinct().ToArray();
|
||||
var paths = entityService.GetAllPaths(objectType, asn).ToDictionary(x => x.Id, x => x.Path);
|
||||
|
||||
paths[Constants.System.Root] = Constants.System.Root.ToString(); // entityService does not get that one
|
||||
|
||||
var binPath = GetBinPath(objectType);
|
||||
|
||||
var lsn = new List<int>();
|
||||
foreach (var sn in groupSn)
|
||||
{
|
||||
string snp;
|
||||
if (paths.TryGetValue(sn, out snp) == false) continue; // ignore rogue node (no path)
|
||||
|
||||
if (StartsWithPath(snp, binPath)) continue; // ignore bin
|
||||
|
||||
if (lsn.Any(x => StartsWithPath(snp, paths[x]))) continue; // skip if something above this sn
|
||||
lsn.RemoveAll(x => StartsWithPath(paths[x], snp)); // remove anything below this sn
|
||||
lsn.Add(sn);
|
||||
}
|
||||
|
||||
return formattedPath.Contains(formattedStartNodeId);
|
||||
}
|
||||
var usn = new List<int>();
|
||||
foreach (var sn in userSn)
|
||||
{
|
||||
if (groupSn.Contains(sn)) continue; // ignore, already there
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the user has access to the media item based on their start noe
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="media"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool HasPathAccess(this IUser user, IMedia media)
|
||||
{
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
if (media == null) throw new ArgumentNullException(nameof(media));
|
||||
return HasPathAccess(media.Path, user.StartMediaId, Constants.System.RecycleBinMedia);
|
||||
string snp;
|
||||
if (paths.TryGetValue(sn, out snp) == false) continue; // ignore rogue node (no path)
|
||||
|
||||
if (StartsWithPath(snp, binPath)) continue; // ignore bin
|
||||
|
||||
if (usn.Any(x => StartsWithPath(paths[x], snp))) continue; // skip if something below this sn
|
||||
usn.RemoveAll(x => StartsWithPath(snp, paths[x])); // remove anything above this sn
|
||||
usn.Add(sn);
|
||||
}
|
||||
|
||||
foreach (var sn in usn)
|
||||
{
|
||||
var snp = paths[sn]; // has to be here now
|
||||
lsn.RemoveAll(x => StartsWithPath(snp, paths[x]) || StartsWithPath(paths[x], snp)); // remove anything above or below this sn
|
||||
lsn.Add(sn);
|
||||
}
|
||||
|
||||
return lsn.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user