mirror of
https://gitlab.com/comunic/comunicapiv2
synced 2024-11-22 13:29:22 +00:00
Can update group settings
This commit is contained in:
parent
7e28722574
commit
0c8ce5c922
@ -4,6 +4,10 @@ import { GroupsAccessLevel, GroupInfo, GroupVisibilityLevel, GroupPostsCreationL
|
||||
import { GroupMembershipLevels } from "../entities/GroupMember";
|
||||
import { time } from "../utils/DateUtils";
|
||||
import { LikesHelper, LikesType } from "../helpers/LikesHelper";
|
||||
import { GroupSettings } from "../entities/GroupSettings";
|
||||
import { removeHTMLNodes, checkURL } from "../utils/StringUtils";
|
||||
import { findKey } from "../utils/ArrayUtils";
|
||||
import { checkVirtualDirectoryAvailability, VirtualDirType } from "../utils/VirtualDirsUtils";
|
||||
|
||||
/**
|
||||
* Groups API controller
|
||||
@ -14,7 +18,7 @@ import { LikesHelper, LikesType } from "../helpers/LikesHelper";
|
||||
/**
|
||||
* API groups registration levels
|
||||
*/
|
||||
const GROUPS_REGISTRATION_LEVELS = [];
|
||||
const GROUPS_REGISTRATION_LEVELS = {};
|
||||
GROUPS_REGISTRATION_LEVELS[GroupRegistrationLevel.OPEN_REGISTRATION] = "open";
|
||||
GROUPS_REGISTRATION_LEVELS[GroupRegistrationLevel.MODERATED_REGISTRATION] = "moderated";
|
||||
GROUPS_REGISTRATION_LEVELS[GroupRegistrationLevel.CLOSED_REGISTRATION] = "closed";
|
||||
@ -22,7 +26,7 @@ GROUPS_REGISTRATION_LEVELS[GroupRegistrationLevel.CLOSED_REGISTRATION] = "closed
|
||||
/**
|
||||
* API groups membership levels
|
||||
*/
|
||||
const GROUPS_MEMBERSHIP_LEVELS = [];
|
||||
const GROUPS_MEMBERSHIP_LEVELS = {};
|
||||
GROUPS_MEMBERSHIP_LEVELS[GroupMembershipLevels.ADMINISTRATOR] = "administrator";
|
||||
GROUPS_MEMBERSHIP_LEVELS[GroupMembershipLevels.MODERATOR] = "moderator";
|
||||
GROUPS_MEMBERSHIP_LEVELS[GroupMembershipLevels.MEMBER] = "member";
|
||||
@ -34,7 +38,7 @@ GROUPS_MEMBERSHIP_LEVELS[GroupMembershipLevels.VISITOR] = "visitor";
|
||||
/**
|
||||
* API groups visibility levels
|
||||
*/
|
||||
const GROUPS_VISIBILITY_LEVELS = [];
|
||||
const GROUPS_VISIBILITY_LEVELS = {};
|
||||
GROUPS_VISIBILITY_LEVELS[GroupVisibilityLevel.OPEN_GROUP] = "open";
|
||||
GROUPS_VISIBILITY_LEVELS[GroupVisibilityLevel.PRIVATE_GROUP] = "private";
|
||||
GROUPS_VISIBILITY_LEVELS[GroupVisibilityLevel.SECRETE_GROUP] = "secrete";
|
||||
@ -144,6 +148,74 @@ export class GroupsController {
|
||||
h.send(await this.GroupInfoToAPI(group, h, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set (update) group settings
|
||||
*
|
||||
* @param h Request handler
|
||||
*/
|
||||
public static async SetSettings(h: RequestHandler) {
|
||||
const groupID = await h.postGroupIDWithAccess("id", GroupsAccessLevel.ADMIN_ACCESS);
|
||||
|
||||
// Check group visibility
|
||||
const visibilityKey = findKey(GROUPS_VISIBILITY_LEVELS, h.postString("visibility", 3));
|
||||
if(visibilityKey == null)
|
||||
h.error(400, "Group visibility level not recognized!");
|
||||
|
||||
// Check group registration level
|
||||
const registrationKey = findKey(GROUPS_REGISTRATION_LEVELS, h.postString("registration_level", 3));
|
||||
if(registrationKey == null)
|
||||
h.error(400, "Group registration level not recognized!");
|
||||
|
||||
// Check post creation level
|
||||
const postLevelKey = findKey(GROUPS_POSTS_LEVELS, h.postString("posts_level", 3));
|
||||
if(postLevelKey == null)
|
||||
h.error(400, "Group post creation level not recognized!");
|
||||
|
||||
|
||||
// Check URL
|
||||
const url = h.postString("url", 0);
|
||||
if(url.length > 0 && ! checkURL(url))
|
||||
h.error(401, "Invalid group URL!");
|
||||
|
||||
|
||||
// Check virtual directory
|
||||
let virtualDirectory = "";
|
||||
if(h.hasPostString("virtual_directory", 1)) {
|
||||
virtualDirectory = h.postVirtualDirectory("virtual_directory");
|
||||
|
||||
// Check out whether virtual directory is available or not
|
||||
if(!await checkVirtualDirectoryAvailability(virtualDirectory, groupID, VirtualDirType.GROUP))
|
||||
h.error(401, "Requested virtual directory is not available!");
|
||||
}
|
||||
|
||||
const settings = new GroupSettings({
|
||||
// Basic information
|
||||
id: groupID,
|
||||
name: removeHTMLNodes(h.postString("name", 3)),
|
||||
visiblity: <GroupVisibilityLevel>Number(visibilityKey),
|
||||
registrationLevel: <GroupRegistrationLevel>Number(registrationKey),
|
||||
postsCreationLevel: <GroupPostsCreationLevel>Number(postLevelKey),
|
||||
|
||||
// Useless info
|
||||
membersCount: -1,
|
||||
timeCreate: -1,
|
||||
|
||||
// Optionnal
|
||||
description: removeHTMLNodes(h.postString("description", 0)),
|
||||
|
||||
// Optionnal
|
||||
url: url,
|
||||
|
||||
// Optionnal
|
||||
virtualDirectory: virtualDirectory,
|
||||
|
||||
});
|
||||
|
||||
await GroupsHelper.SetSettings(settings);
|
||||
|
||||
h.success("Group settings have been successfully updated!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a GroupInfo object into a valid API object
|
||||
*
|
||||
|
@ -96,4 +96,6 @@ export const Routes : Route[] = [
|
||||
{path: "/groups/get_advanced_info", cb: (h) => GroupsController.GetAdvancedInfo(h), needLogin: false},
|
||||
|
||||
{path: "/groups/get_settings", cb: (h) => GroupsController.GetSettings(h)},
|
||||
|
||||
{path: "/groups/set_settings", cb: (h) => GroupsController.SetSettings(h)},
|
||||
]
|
11
src/entities/GroupSettings.ts
Normal file
11
src/entities/GroupSettings.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { GroupInfo } from "./Group";
|
||||
|
||||
/**
|
||||
* Group settings
|
||||
*
|
||||
* @author Pierre HUBERT
|
||||
*/
|
||||
|
||||
export class GroupSettings extends GroupInfo {
|
||||
|
||||
}
|
@ -9,6 +9,7 @@ import * as sharp from 'sharp';
|
||||
import { UserHelper } from "../helpers/UserHelper";
|
||||
import { GroupsAccessLevel } from "./Group";
|
||||
import { GroupsHelper } from "../helpers/GroupsHelper";
|
||||
import { checkVirtualDirectory } from "../utils/VirtualDirsUtils";
|
||||
|
||||
/**
|
||||
* Response to a request
|
||||
@ -67,6 +68,16 @@ export class RequestHandler {
|
||||
return this.getPostParam(name) != undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check out whether a POST string is present in the request or not
|
||||
*
|
||||
* @param name The name of the POST field to check
|
||||
* @param minLength Minimal length of the parameter
|
||||
*/
|
||||
public hasPostString(name: string, minLength: number = 0) : boolean {
|
||||
return this.hasPostParameter(name) && this.getPostParam(name).length >= minLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an email address included in a post request
|
||||
*
|
||||
@ -233,6 +244,21 @@ export class RequestHandler {
|
||||
return groupID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a virtual directory included in a POST request
|
||||
*
|
||||
* @param name The name of the POST variable
|
||||
* @return The virtual directory, if found as valid
|
||||
*/
|
||||
public postVirtualDirectory(name: string) : string {
|
||||
const dir = this.postString(name);
|
||||
|
||||
if(!checkVirtualDirectory(dir))
|
||||
this.error(401, "Specified directory seems to be invalid!");
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about an uploaded file
|
||||
*
|
||||
|
@ -2,6 +2,7 @@ import { crypt, sha1, randomStr } from "../utils/CryptUtils";
|
||||
import { APIClient } from "../entities/APIClient";
|
||||
import { UserLoginTokens } from "../entities/UserLoginTokens";
|
||||
import { DatabaseHelper } from "./DatabaseHelper";
|
||||
import { UserHelper } from "./UserHelper";
|
||||
|
||||
/**
|
||||
* Account helper
|
||||
@ -139,4 +140,17 @@ export class AccountHelper {
|
||||
token2: row.token2
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check out whether a virtual directory is available or not
|
||||
*
|
||||
* @param dir Virtual directory to check
|
||||
* @param userID Target user ID
|
||||
*/
|
||||
public static async CheckUserDirectoryAvailability(dir: string, userID: number = -1) : Promise<boolean> {
|
||||
const foundUser = await UserHelper.FindByFolder(dir);
|
||||
|
||||
return foundUser < 1 || userID == foundUser;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ import { GroupsAccessLevel, GroupVisibilityLevel, GroupInfo } from "../entities/
|
||||
import { GroupMembershipLevels, GroupMember } from "../entities/GroupMember";
|
||||
import { NewGroup } from "../entities/NewGroup";
|
||||
import { time } from "../utils/DateUtils";
|
||||
import { GroupSettings } from "../entities/GroupSettings";
|
||||
|
||||
/**
|
||||
* Groups helper
|
||||
@ -98,6 +99,23 @@ export class GroupsHelper {
|
||||
return this.DbToGroupInfo(row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update (set) group settings
|
||||
*
|
||||
* @param settings Group settings
|
||||
*/
|
||||
public static async SetSettings(settings: GroupSettings) {
|
||||
const dbEntry = this.GroupSettingsToDB(settings);
|
||||
|
||||
await DatabaseHelper.UpdateRows({
|
||||
table: GROUPS_LIST_TABLE,
|
||||
where: {
|
||||
id: settings.id
|
||||
},
|
||||
set: dbEntry
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the visibility level of a group
|
||||
*
|
||||
@ -222,6 +240,36 @@ export class GroupsHelper {
|
||||
return this.DbToGroupMember(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a group by its virtual directory
|
||||
*
|
||||
* @param dir Target directory
|
||||
* @returns The ID of the target directory / -1 if none found
|
||||
*/
|
||||
public static async FindByVirtualDirectory(dir: string) : Promise<number> {
|
||||
const result = await DatabaseHelper.QueryRow({
|
||||
table: GROUPS_LIST_TABLE,
|
||||
where: {
|
||||
virtual_directory: dir
|
||||
},
|
||||
fields: ["id"]
|
||||
});
|
||||
|
||||
return result == null ? -1 : result.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check out whether a virtual directory is available or not
|
||||
*
|
||||
* @param dir The directory to check
|
||||
* @param groupID The ID of the group making the request
|
||||
*/
|
||||
public static async CheckDirectoryAvailability(dir: string, groupID: number = -1) : Promise<boolean> {
|
||||
const currID = await this.FindByVirtualDirectory(dir);
|
||||
|
||||
return currID < 1 || currID == groupID;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Count the number of members of a group
|
||||
@ -277,4 +325,40 @@ export class GroupsHelper {
|
||||
following: row.following == 1
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a GroupSettings object into a database entry object
|
||||
*
|
||||
* @param settings Group settings object to transform
|
||||
* @return Generated database entry
|
||||
*/
|
||||
private static GroupSettingsToDB(settings: GroupSettings) : Object {
|
||||
let data = {};
|
||||
|
||||
if(settings.name != null)
|
||||
data['name'] = settings.name;
|
||||
|
||||
if(settings.hasLogo)
|
||||
data["path_logo"] = settings.logo;
|
||||
|
||||
if(settings.visiblity != null)
|
||||
data["visibility"] = settings.visiblity;
|
||||
|
||||
if(settings.registrationLevel != null)
|
||||
data["registration_level"] = settings.registrationLevel;
|
||||
|
||||
if(settings.postsCreationLevel != null)
|
||||
data["posts_level"] = settings.postsCreationLevel;
|
||||
|
||||
if(settings.virtualDirectory != null)
|
||||
data["virtual_directory"] = settings.virtualDirectory;
|
||||
|
||||
if(settings.description != null)
|
||||
data["description"] = settings.description;
|
||||
|
||||
if(settings.url != null)
|
||||
data["url"] = settings.url;
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
@ -68,6 +68,24 @@ export class UserHelper {
|
||||
return request.map((e) => e.ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for user by virtual directory
|
||||
*
|
||||
* @param dir Target directory
|
||||
* @returns The ID of the user found / -1 if none found
|
||||
*/
|
||||
public static async FindByFolder(dir: string) : Promise<number> {
|
||||
const result = await DatabaseHelper.QueryRow({
|
||||
table: TABLE_NAME,
|
||||
where: {
|
||||
sous_repertoire: dir
|
||||
},
|
||||
fields: ["ID"]
|
||||
});
|
||||
|
||||
return result == null ? -1 : Number(result.ID);
|
||||
}
|
||||
|
||||
|
||||
private static async DbToUser(row: any) : Promise<User> {
|
||||
return new User({
|
||||
|
24
src/utils/ArrayUtils.ts
Normal file
24
src/utils/ArrayUtils.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Array utilities
|
||||
*
|
||||
* @author Pierre HUBERT
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find the key matching a given value in an object
|
||||
*
|
||||
* @param object Object to search in
|
||||
* @param value The value to search for
|
||||
* @returns Matching key, or null if not found
|
||||
*/
|
||||
export function findKey(object: Object, value: any): string {
|
||||
for (const key in object) {
|
||||
if (!object.hasOwnProperty(key))
|
||||
continue;
|
||||
|
||||
if(object[key] == value)
|
||||
return key;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
@ -14,6 +14,20 @@ export function checkMail(emailAddress: string): boolean {
|
||||
return (emailAddress.match(/^[a-zA-Z0-9_.]+@[a-zA-Z0-9-.]{1,}[.][a-zA-Z]{2,8}$/) === null ? false : true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a URL validity
|
||||
*
|
||||
* Source: https://gist.github.com/729294
|
||||
*
|
||||
* @param {string} url The URL to check
|
||||
* @return {boolean} TRUE if the URL is valid
|
||||
*/
|
||||
export function checkURL(url: string) : boolean {
|
||||
const regex = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i
|
||||
|
||||
return url.match(regex) == null ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix text encoding
|
||||
*
|
||||
|
49
src/utils/VirtualDirsUtils.ts
Normal file
49
src/utils/VirtualDirsUtils.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { AccountHelper } from "../helpers/AccountHelper";
|
||||
import { GroupsHelper } from "../helpers/GroupsHelper";
|
||||
|
||||
/**
|
||||
* Virtual directories utilities
|
||||
*
|
||||
* @author Pierre HUBERT
|
||||
*/
|
||||
|
||||
export enum VirtualDirType {
|
||||
USER,
|
||||
GROUP
|
||||
}
|
||||
|
||||
/**
|
||||
* Check out whether a virtual directory is valid or not
|
||||
*
|
||||
* @param dir The virtual directory to check
|
||||
*/
|
||||
export function checkVirtualDirectory(dir: string) : boolean {
|
||||
if(dir.length < 4) return false;
|
||||
|
||||
for(let el of [".html", ".txt", ".php", "à", "â", "é", "ê", "@", "/", "\"", "'", '"', "<", ">", "?", "&", "#"])
|
||||
if(dir.includes(el))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the availability of a virtual directory
|
||||
*
|
||||
* @param dir Directory to check
|
||||
* @param id The ID of the element to check
|
||||
* @param type The type of the element
|
||||
*/
|
||||
export async function checkVirtualDirectoryAvailability(dir: string, id: number, type: VirtualDirType) : Promise<boolean> {
|
||||
if(!checkVirtualDirectory(dir)) return false;
|
||||
|
||||
if(type == VirtualDirType.USER) {
|
||||
return await AccountHelper.CheckUserDirectoryAvailability(dir, id)
|
||||
&& await GroupsHelper.CheckDirectoryAvailability(dir);
|
||||
}
|
||||
|
||||
else {
|
||||
return await AccountHelper.CheckUserDirectoryAvailability(dir)
|
||||
&& await GroupsHelper.CheckDirectoryAvailability(dir, id);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user