diff --git a/src/controllers/GroupsController.ts b/src/controllers/GroupsController.ts index 1dd4fdc..1c8d225 100644 --- a/src/controllers/GroupsController.ts +++ b/src/controllers/GroupsController.ts @@ -1,6 +1,7 @@ import { RequestHandler } from "../entities/RequestHandler"; import { GroupsHelper } from "../helpers/GroupsHelper"; -import { GroupsAccessLevel } from "../entities/Group"; +import { GroupsAccessLevel, GroupInfo, GroupVisibilityLevel, GroupPostsCreationLevel, GroupRegistrationLevel } from "../entities/Group"; +import { GroupMembershipLevels } from "../entities/GroupMember"; /** * Groups API controller @@ -8,6 +9,43 @@ import { GroupsAccessLevel } from "../entities/Group"; * @author Pierre HUBERT */ +/** + * API 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"; + +/** + * API 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"; +GROUPS_MEMBERSHIP_LEVELS[GroupMembershipLevels.INVITED] = "invited"; +GROUPS_MEMBERSHIP_LEVELS[GroupMembershipLevels.PENDING] = "pending"; +GROUPS_MEMBERSHIP_LEVELS[GroupMembershipLevels.VISITOR] = "visitor"; + + +/** + * API 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"; + + +/** + * API posts creation levels + */ +const GROUPS_POSTS_LEVELS = []; +GROUPS_POSTS_LEVELS[GroupPostsCreationLevel.POSTS_LEVEL_MODERATORS] = "moderators"; +GROUPS_POSTS_LEVELS[GroupPostsCreationLevel.POSTS_LEVEL_ALL_MEMBERS] = "members"; + + export class GroupsController { /** @@ -26,6 +64,27 @@ export class GroupsController { */ public static async GetInfoSingle(h: RequestHandler) { const groupID = await h.postGroupIDWithAccess("id", GroupsAccessLevel.LIMITED_ACCESS); - h.send("Good progress!"); + const groupInfo = await GroupsHelper.GetInfo(groupID); + + h.send(this.GroupInfoToAPI(groupInfo)); + } + + /** + * Turn a GroupInfo object into a valid API object + * + * @param info Information about the group + * @returns Generated object + */ + private static GroupInfoToAPI(info: GroupInfo) : any { + return { + id: info.id, + name: info.name, + icon_url: info.logoURL, + number_members: info.membersCount, + visibility: GROUPS_VISIBILITY_LEVELS[info.visiblity], + registration_level: GROUPS_REGISTRATION_LEVELS[info.registrationLevel], + posts_level: GROUPS_POSTS_LEVELS[info.postsCreationLevel], + virtual_directory: info.virtualDirectory, + } } } \ No newline at end of file diff --git a/src/entities/Group.ts b/src/entities/Group.ts index 715a39e..7be02a1 100644 --- a/src/entities/Group.ts +++ b/src/entities/Group.ts @@ -1,9 +1,14 @@ +import { pathUserData } from "../utils/UserDataUtils"; +import { join } from "path"; + /** * Single group information * * @author Pierre HUBERT */ +export const PATH_GROUP_LOGO = "groups_logo"; + /** * Group visibility level */ @@ -23,4 +28,65 @@ export enum GroupsAccessLevel { MEMBER_ACCESS = 3, //Member access (same as view access but as member) MODERATOR_ACCESS = 4, //Can create posts, even if posts creation is restricted ADMIN_ACCESS = 5, //Can do everything +} + +/** + * Registration level of groups + */ +export enum GroupRegistrationLevel { + OPEN_REGISTRATION = 0, + MODERATED_REGISTRATION = 1, + CLOSED_REGISTRATION = 2, +} + +export enum GroupPostsCreationLevel { + POSTS_LEVEL_MODERATORS = 0, //Only the moderators and the administrator can create posts + POSTS_LEVEL_ALL_MEMBERS = 1, //All the members of the group can create posts +} + +export interface GroupInfoConstructor { + id: number, + name: string, + membersCount: number, + visiblity: GroupVisibilityLevel, + registrationLevel: GroupRegistrationLevel, + postsCreationLevel: GroupPostsCreationLevel, + logo ?: string, + virtualDirectory ?: string +} + +export class GroupInfo implements GroupInfoConstructor { + id: number; + name: string; + membersCount: number; + visiblity: GroupVisibilityLevel; + registrationLevel: GroupRegistrationLevel; + postsCreationLevel: GroupPostsCreationLevel; + logo?: string; + virtualDirectory?: string; + + constructor(info: GroupInfoConstructor) { + for (const key in info) { + if (info.hasOwnProperty(key)) { + this[key] = info[key]; + } + } + } + + get hasLogo() : boolean { + return this.logo + && this.logo != "null" + && this.logo != undefined; + } + + get logoPath() : string { + if(this.hasLogo) + return this.logo + else + return join(PATH_GROUP_LOGO, "default.png"); + } + + get logoURL() : string { + return pathUserData(this.logoPath, false); + } } \ No newline at end of file diff --git a/src/helpers/DatabaseHelper.ts b/src/helpers/DatabaseHelper.ts index b0d933a..5a8ee79 100644 --- a/src/helpers/DatabaseHelper.ts +++ b/src/helpers/DatabaseHelper.ts @@ -35,7 +35,9 @@ export interface UpdateInformation { export interface CountQueryInformation { table: string, - where ?: Object + where ?: Object, + customWhere ?: string, + customWhereArgs ?: Array } export class DatabaseHelper { @@ -319,6 +321,16 @@ export class DatabaseHelper { sql = sql.replace("WHERE AND", "WHERE"); } + if(info.customWhere) { + if(info.where) + sql += " AND (" + info.customWhere + ")"; + else + sql += "WHERE " + info.customWhere; + + if(info.customWhereArgs) + info.customWhereArgs.forEach(e => args.push(e)); + } + return await new Promise((r, e) => { this.connection.query(sql, args, (err, results, f) => { if(err){ diff --git a/src/helpers/GroupsHelper.ts b/src/helpers/GroupsHelper.ts index 486ad57..0818dbb 100644 --- a/src/helpers/GroupsHelper.ts +++ b/src/helpers/GroupsHelper.ts @@ -1,5 +1,5 @@ import { DatabaseHelper } from "./DatabaseHelper"; -import { GroupsAccessLevel, GroupVisibilityLevel } from "../entities/Group"; +import { GroupsAccessLevel, GroupVisibilityLevel, GroupInfo } from "../entities/Group"; import { GroupMembershipLevels } from "../entities/GroupMember"; /** @@ -44,6 +44,27 @@ export class GroupsHelper { return list.map(e => e.groups_id); } + /** + * Get information about a group + * + * @param groupID Target group ID + * @returns Information about the group + * @throws {Error} if the group was not found + */ + public static async GetInfo(groupID: number) : Promise { + const row = await DatabaseHelper.QueryRow({ + table: GROUPS_LIST_TABLE, + where: { + id: groupID.toString() + } + }); + + if(row == null || !row) + throw new Error("Could not get information about the group!"); + + return this.DbToGroupInfo(row); + } + /** * Get the visibility level of a group * @@ -126,4 +147,39 @@ export class GroupsHelper { // Especially in the case of secret groupe return GroupsAccessLevel.NO_ACCESS; } + + /** + * Count the number of members of a group + * + * @param groupID Target group ID + */ + private static async CountMembers(groupID: number) : Promise { + return await DatabaseHelper.Count({ + table: GROUPS_MEMBERS_TABLE, + where: { + groups_id: groupID + }, + customWhere: "level <= ?", + customWhereArgs: [GroupMembershipLevels.MEMBER.toString()] + }); + } + + /** + * Turn a database row into a {GroupInfo} object + * + * @param row Database entry + * @returns Generated object + */ + private static async DbToGroupInfo(row: any) : Promise { + return new GroupInfo({ + id: row.id, + name: row.name, + membersCount: await this.CountMembers(row.id), + visiblity: row.visibility, + registrationLevel: row.registration_level, + postsCreationLevel: row.posts_level, + logo: (row.path_logo != null && row.path_logo && row.path_logo != "null" ? row.path_logo : undefined), + virtualDirectory: (row.virtual_directory != null && row.virtual_directory && row.virtual_directory != "null" ? row.virtual_directory : undefined) + }); + } } \ No newline at end of file