public static async void NotifyCategoryChange(ServerPlanetCategory category) { string json = JsonSerializer.Serialize(category); // Send update to members await Current.Clients.Group($"p-{category.Planet_Id}").SendAsync("CategoryUpdate", json); }
public async Task <CategoryPermissionsNode> GetCategoryNodeAsync(ServerPlanetCategory category, ValourDB db = null) { bool createdb = false; if (db == null) { db = new ValourDB(ValourDB.DBOptions); } var res = await db.CategoryPermissionsNodes.FirstOrDefaultAsync(x => x.Category_Id == category.Id && x.Role_Id == Id); if (createdb) { await db.DisposeAsync(); } return(res); }
private static async Task InsertItem(HttpContext ctx, ValourDB db, ulong category_id, [FromHeader] string authorization) { AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db); if (auth == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token is invalid [token: {authorization}]"); return; } ServerPlanetCategory category = await db.PlanetCategories.Include(x => x.Planet) .ThenInclude(x => x.Members.Where(x => x.User_Id == auth.User_Id)) .FirstOrDefaultAsync(x => x.Id == category_id); if (category == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Category not found [id: {category_id}]"); return; } var member = category.Planet.Members.FirstOrDefault(); if (member == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member not found"); return; } if (!await category.HasPermission(member, CategoryPermissions.View, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks CategoryPermissions.View"); return; } if (!auth.HasScope(UserPermissions.PlanetManagement)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token lacks UserPermissions.PlanetManagement"); return; } if (!await category.HasPermission(member, CategoryPermissions.ManageCategory, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks CategoryPermissions.ManageCategory"); return; } ChannelListItem in_item = await JsonSerializer.DeserializeAsync <ChannelListItem>(ctx.Request.Body); if (in_item == null || in_item.Planet_Id == 0) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Include item data."); return; } IServerChannelListItem item = await IServerChannelListItem.FindAsync(in_item.ItemType, in_item.Id, db); if (item == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Item not found [id: {in_item.Id}]"); return; } ServerPlanet item_planet = await db.Planets.FindAsync(item.Planet_Id); if (item_planet == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Item planet not found [id: {in_item.Planet_Id}]"); return; } if (item_planet.Id != category.Planet_Id) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Item belongs to different planet"); return; } if (item.Parent_Id == category.Id) { ctx.Response.StatusCode = 200; await ctx.Response.WriteAsync($"No change"); return; } // Ensure that if this is a category, it is not going into a category that contains itself! if (item.ItemType == ItemType.Category) { ulong?parent_id = category.Parent_Id; while (parent_id != null) { // Recursion is a nono if (parent_id == item.Id) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Operation would result in recursion."); return; } parent_id = (await db.PlanetCategories.FindAsync(parent_id)).Parent_Id; } } item.Parent_Id = category.Id; item.Position = in_item.Position; db.Update(item); await db.SaveChangesAsync(); item.NotifyClientsChange(); ctx.Response.StatusCode = 200; await ctx.Response.WriteAsync("Success"); return; }
private static async Task SetChildOrder(HttpContext ctx, ValourDB db, ulong category_id, [FromHeader] string authorization) { AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db); if (auth == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token is invalid [token: {authorization}]"); return; } ServerPlanetCategory category = await db.PlanetCategories.Include(x => x.Planet) .ThenInclude(x => x.Members.Where(x => x.User_Id == auth.User_Id)) .FirstOrDefaultAsync(x => x.Id == category_id); if (category == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Category not found [id: {category_id}]"); return; } var member = category.Planet.Members.FirstOrDefault(); if (member == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member not found"); return; } if (!await category.HasPermission(member, CategoryPermissions.View, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks CategoryPermissions.View"); return; } if (!auth.HasScope(UserPermissions.PlanetManagement)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token lacks UserPermissions.PlanetManagement"); return; } if (!await category.HasPermission(member, CategoryPermissions.ManageCategory, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks CategoryPermissions.ManageCategory"); return; } string body = await ctx.Request.ReadBodyStringAsync(); if (string.IsNullOrEmpty(body)) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Include order data."); return; } List <CategoryContentData> orderData = JsonSerializer.Deserialize <List <CategoryContentData> >(body); if (orderData == null || orderData.Count == 0) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Include order data."); return; } List <IServerChannelListItem> changed = new List <IServerChannelListItem>(); foreach (CategoryContentData order in orderData) { IServerChannelListItem item = await IServerChannelListItem.FindAsync(order.ItemType, order.Id, db); if (item == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Item with id {order.Id} not found"); return; } if (item.Planet_Id != category.Planet_Id) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Item with id {order.Id} belongs to wrong planet {item.Planet_Id}"); return; } // Only act if there is a difference if (item.Parent_Id != category_id || item.Position != order.Position) { // Prevent putting an item inside of itself if (item.Id != category_id) { item.Parent_Id = category_id; item.Position = order.Position; db.Update(item); changed.Add(item); } } } // If all is successful, save and send updates foreach (var item in changed) { // Send update to clients item.NotifyClientsChange(); } await db.SaveChangesAsync(); ctx.Response.StatusCode = 200; await ctx.Response.WriteAsync("Success"); return; }
private static async Task GetChildren(HttpContext ctx, ValourDB db, ulong category_id, [FromHeader] string authorization) { AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db); if (auth == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token is invalid [token: {authorization}]"); return; } ServerPlanetCategory category = await db.PlanetCategories.Include(x => x.Planet) .ThenInclude(x => x.Members.Where(x => x.User_Id == auth.User_Id)) .Include(x => x.Planet) .ThenInclude(x => x.ChatChannels) .Include(x => x.Planet) .ThenInclude(x => x.Categories) .FirstOrDefaultAsync(x => x.Id == category_id); if (category == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Category not found [id: {category_id}]"); return; } var member = category.Planet.Members.FirstOrDefault(); if (member == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member not found"); return; } if (!await category.HasPermission(member, CategoryPermissions.View, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks CategoryPermissions.View"); return; } List <ChannelListItem> children = new List <ChannelListItem>(); foreach (var channel in category.Planet.ChatChannels) { if (await channel.HasPermission(member, ChatChannelPermissions.View, db)) { children.Add(channel); } } foreach (var cat in category.Planet.Categories) { if (await cat.HasPermission(member, CategoryPermissions.View, db)) { children.Add(cat); } } ctx.Response.StatusCode = 200; await ctx.Response.WriteAsJsonAsync(children); return; }
private static async Task Category(HttpContext ctx, ValourDB db, ulong category_id, [FromHeader] string authorization) { AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db); if (auth == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token is invalid [token: {authorization}]"); return; } ServerPlanetCategory category = await db.PlanetCategories.Include(x => x.Planet) .ThenInclude(x => x.Members.Where(x => x.User_Id == auth.User_Id)) .FirstOrDefaultAsync(x => x.Id == category_id); if (category == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Category not found [id: {category_id}]"); return; } var member = category.Planet.Members.FirstOrDefault(); if (member == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member not found"); return; } if (!await category.HasPermission(member, CategoryPermissions.View, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks CategoryPermissions.View"); return; } switch (ctx.Request.Method) { case "GET": { ctx.Response.StatusCode = 200; await ctx.Response.WriteAsJsonAsync((PlanetCategory)category); return; } case "DELETE": { if (!auth.HasScope(UserPermissions.PlanetManagement)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token lacks UserPermissions.PlanetManagement"); return; } if (!await category.HasPermission(member, CategoryPermissions.ManageCategory, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks CategoryPermissions.ManageCategory"); return; } TaskResult result = await category.TryDeleteAsync(db); if (!result.Success) { ctx.Response.StatusCode = 400; } else { ctx.Response.StatusCode = 200; } await ctx.Response.WriteAsync(result.Message); return; } } }
private static async Task ParentId(HttpContext ctx, ValourDB db, ulong category_id, int?position, [FromHeader] string authorization) { if (position == null) { position = -1; } AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db); if (auth == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token is invalid [token: {authorization}]"); return; } ServerPlanetCategory category = await db.PlanetCategories.Include(x => x.Planet) .ThenInclude(x => x.Members.Where(x => x.User_Id == auth.User_Id)) .FirstOrDefaultAsync(x => x.Id == category_id); if (category == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Category not found [id: {category_id}]"); return; } var member = category.Planet.Members.FirstOrDefault(); if (member == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member not found"); return; } if (!await category.HasPermission(member, CategoryPermissions.View, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks CategoryPermissions.View"); return; } switch (ctx.Request.Method) { case "GET": { ctx.Response.StatusCode = 200; await ctx.Response.WriteAsJsonAsync(category.Parent_Id); return; } case "PUT": { if (!auth.HasScope(UserPermissions.PlanetManagement)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token lacks UserPermissions.PlanetManagement"); return; } string body = await ctx.Request.ReadBodyStringAsync(); ulong?parent_id; if (body == "null" || body == "0" || body == "none" || string.IsNullOrWhiteSpace(body)) { parent_id = null; } else { ulong parsed_ul; bool parsed = ulong.TryParse(body, out parsed_ul); parent_id = parsed_ul; if (!parsed) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Given value is invalid"); return; } } TaskResult <int> result = await category.TrySetParentAsync(member, parent_id, (int)position, db); ctx.Response.StatusCode = result.Data; await ctx.Response.WriteAsync(result.Message); return; } } }
private static async Task CreateCategory(HttpContext ctx, ValourDB db, [FromHeader] string authorization) { ServerPlanetCategory category_data = await JsonSerializer.DeserializeAsync <ServerPlanetCategory>(ctx.Request.Body); if (category_data == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Please include category in body"); return; } if (string.IsNullOrWhiteSpace(category_data.Name)) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Please include a category name"); return; } // Request parameter validation // TaskResult name_valid = ServerPlanetCategory.ValidateName(category_data.Name); if (!name_valid.Success) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Name is not valid [name: {category_data.Name}]"); return; } // Request authorization // AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db); if (!auth.HasScope(UserPermissions.PlanetManagement)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Token lacks UserPermissions.PlanetManagement scope"); return; } ServerPlanet planet = await db.Planets.Include(x => x.Members.Where(x => x.User_Id == auth.User_Id)) .FirstOrDefaultAsync(x => x.Id == category_data.Planet_Id); var member = planet.Members.FirstOrDefault(); if (!await planet.HasPermissionAsync(member, PlanetPermissions.ManageChannels, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks PlanetPermissions.ManageChannels node"); return; } // Ensure parent category exists ulong?parent_id = null; ServerPlanetCategory parent = await db.PlanetCategories.FindAsync(category_data.Parent_Id); ushort child_count = 0; if (parent != null) { parent_id = parent.Id; if (parent.Planet_Id != planet.Id) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Parent id does not match planet"); return; } child_count += (ushort)await db.PlanetChatChannels.CountAsync(x => x.Parent_Id == parent_id); child_count += (ushort)await db.PlanetCategories.CountAsync(x => x.Parent_Id == parent_id); } // Request action // // Creates the category ServerPlanetCategory category = new ServerPlanetCategory() { Id = IdManager.Generate(), Name = category_data.Name, Planet_Id = category_data.Planet_Id, Parent_Id = category_data.Parent_Id, Description = category_data.Description, Position = child_count }; // Add channel to database await db.PlanetCategories.AddAsync(category); // Save changes to DB await db.SaveChangesAsync(); // Send channel refresh PlanetHub.NotifyCategoryChange(category); ctx.Response.StatusCode = 201; await ctx.Response.WriteAsync(category.Id.ToString()); }
private static async Task Create(HttpContext ctx, ValourDB db, [FromHeader] string authorization, [Required] string name, [Required] string image_url) { ServerAuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db); if (auth == null) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync($"Token is invalid [token: {authorization}]"); return; } TaskResult nameValid = ServerPlanet.ValidateName(name); if (!nameValid.Success) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync(nameValid.Message); return; } ServerUser user = await db.Users.FindAsync(auth.User_Id); if (!user.Valour_Staff) { var owned_planets = await db.Planets.CountAsync(x => x.Owner_Id == user.Id); if (owned_planets > MAX_OWNED_PLANETS) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Max owned planets reached"); return; } } // Image handling via proxy ProxyResponse proxyResponse = await MPSManager.GetProxy(image_url); bool is_media = MPSManager.Media_Types.Contains(proxyResponse.Item.Mime_Type); if (proxyResponse.Item == null || !is_media) { image_url = "https://valour.gg/image.png"; } else { image_url = proxyResponse.Item.Url; } ulong planet_id = IdManager.Generate(); // Create general category ServerPlanetCategory category = new ServerPlanetCategory() { Id = IdManager.Generate(), Name = "General", Parent_Id = null, Planet_Id = planet_id, Description = "General category", Position = 0 }; // Create general channel ServerPlanetChatChannel channel = new ServerPlanetChatChannel() { Id = IdManager.Generate(), Planet_Id = planet_id, Name = "General", Message_Count = 0, Description = "General chat channel", Parent_Id = category.Id }; // Create default role ServerPlanetRole defaultRole = new ServerPlanetRole() { Id = IdManager.Generate(), Planet_Id = planet_id, Position = uint.MaxValue, Color_Blue = 255, Color_Green = 255, Color_Red = 255, Name = "@everyone" }; ServerPlanet planet = new ServerPlanet() { Id = planet_id, Name = name, Member_Count = 1, Description = "A Valour server.", Image_Url = image_url, Public = true, Owner_Id = user.Id, Default_Role_Id = defaultRole.Id, Main_Channel_Id = channel.Id }; // Add planet to database await db.Planets.AddAsync(planet); await db.SaveChangesAsync(); // We must do this first to prevent foreign key errors // Add category to database await db.PlanetCategories.AddAsync(category); // Add channel to database await db.PlanetChatChannels.AddAsync(channel); // Add default role to database await db.PlanetRoles.AddAsync(defaultRole); // Save changes await db.SaveChangesAsync(); // Add owner to planet await planet.AddMemberAsync(user, db); ctx.Response.StatusCode = 200; await ctx.Response.WriteAsJsonAsync(planet.Id); }
private static async Task Channel(HttpContext ctx, ValourDB db, ulong channel_id, [FromHeader] string authorization) { AuthToken auth = await ServerAuthToken.TryAuthorize(authorization, db); if (auth == null) { await TokenInvalid(ctx); return; } switch (ctx.Request.Method) { case "GET": { ServerPlanetChatChannel channel = await db.PlanetChatChannels.Include(x => x.Planet) .ThenInclude(x => x.Members.Where(x => x.User_Id == auth.User_Id)) .FirstOrDefaultAsync(x => x.Id == channel_id); if (channel == null) { await NotFound("Channel not found", ctx); return; } var member = channel.Planet.Members.FirstOrDefault(); if (member == null) { await Unauthorized("Member not found", ctx); return; } if (!await channel.HasPermission(member, ChatChannelPermissions.View, db)) { await Unauthorized("Member lacks ChatChannelPermissions.View", ctx); return; } ctx.Response.StatusCode = 200; await ctx.Response.WriteAsJsonAsync((PlanetChatChannel)channel); return; } case "DELETE": { ServerPlanetChatChannel channel = await db.PlanetChatChannels.Include(x => x.Planet) .ThenInclude(x => x.Members.Where(x => x.User_Id == auth.User_Id)) .FirstOrDefaultAsync(x => x.Id == channel_id); if (channel == null) { await NotFound("Channel not found", ctx); return; } var member = channel.Planet.Members.FirstOrDefault(); if (!auth.HasScope(UserPermissions.PlanetManagement)) { await Unauthorized("Token lacks UserPermissions.PlanetManagement", ctx); return; } TaskResult <int> result = await channel.TryDeleteAsync(member, db); ctx.Response.StatusCode = result.Data; await ctx.Response.WriteAsync(result.Message); return; } case "POST": { ServerPlanetChatChannel channel_data = JsonSerializer.Deserialize <ServerPlanetChatChannel>(ctx.Request.Body); if (channel_data == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Please include channel in body"); return; } if (string.IsNullOrWhiteSpace(channel_data.Name)) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Please include a channel name"); return; } // Request parameter validation // TaskResult name_valid = ServerPlanetChatChannel.ValidateName(channel_data.Name); if (!name_valid.Success) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync($"Name is not valid [name: {channel_data.Name}]"); return; } // Request authorization // if (!auth.HasScope(UserPermissions.PlanetManagement)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Token lacks UserPermissions.PlanetManagement scope"); return; } ServerPlanetMember member = await db.PlanetMembers .Include(x => x.Planet) .FirstOrDefaultAsync(x => x.Planet_Id == channel_data.Planet_Id && x.User_Id == auth.User_Id); if (!await member.HasPermissionAsync(PlanetPermissions.ManageChannels, db)) { ctx.Response.StatusCode = 401; await ctx.Response.WriteAsync("Member lacks PlanetPermissions.ManageChannels node"); return; } // Ensure parent category exists ServerPlanetCategory parent = await db.PlanetCategories.FindAsync(channel_data.Parent_Id); if (parent == null) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Could not find parent"); return; } if (parent.Planet_Id != member.Planet.Id) { ctx.Response.StatusCode = 400; await ctx.Response.WriteAsync("Parent id does not match planet"); return; } // Request action // // Creates the channel ushort child_count = 0; child_count += (ushort)await db.PlanetChatChannels.CountAsync(x => x.Parent_Id == channel_data.Parent_Id); child_count += (ushort)await db.PlanetCategories.CountAsync(x => x.Parent_Id == channel_data.Parent_Id); ServerPlanetChatChannel channel = new ServerPlanetChatChannel() { Id = IdManager.Generate(), Name = channel_data.Name, Planet_Id = channel_data.Planet_Id, Parent_Id = channel_data.Parent_Id, Message_Count = 0, Description = channel_data.Description, Position = child_count }; // Add channel to database await db.PlanetChatChannels.AddAsync(channel); // Save changes to DB await db.SaveChangesAsync(); // Send channel refresh PlanetHub.NotifyChatChannelChange(channel); ctx.Response.StatusCode = 201; await ctx.Response.WriteAsync(channel.Id.ToString()); return; } } }