mirror of
https://gitlab.com/comunic/comunicapiv2
synced 2024-11-22 13:29:22 +00:00
Start implementation of post system
This commit is contained in:
parent
899ec40bd7
commit
87daf8acbe
68
src/controllers/PostsController.ts
Normal file
68
src/controllers/PostsController.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { RequestHandler } from "../entities/RequestHandler";
|
||||||
|
import { UserHelper } from "../helpers/UserHelper";
|
||||||
|
import { PostsHelper } from "../helpers/PostsHelper";
|
||||||
|
import { Post, PostVisibilityLevel } from "../entities/Post";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posts controller
|
||||||
|
*
|
||||||
|
* @author Pierre HUBERT
|
||||||
|
*/
|
||||||
|
|
||||||
|
const VISIBILITY_LEVELS_API = {};
|
||||||
|
VISIBILITY_LEVELS_API[PostVisibilityLevel.VISIBILITY_PUBLIC] = "public";
|
||||||
|
VISIBILITY_LEVELS_API[PostVisibilityLevel.VISIBILITY_FRIENDS] = "friends";
|
||||||
|
VISIBILITY_LEVELS_API[PostVisibilityLevel.VISIBILITY_USER] = "private";
|
||||||
|
VISIBILITY_LEVELS_API[PostVisibilityLevel.VISIBILITY_GROUP_MEMBERS] = "members";
|
||||||
|
|
||||||
|
export class PostsController {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the posts of a user
|
||||||
|
*
|
||||||
|
* @param h Request handler
|
||||||
|
*/
|
||||||
|
public static async GetListUser(h: RequestHandler) {
|
||||||
|
const userID = await h.postUserId("userID");
|
||||||
|
const startFrom = h.postInt("startFrom", 0);
|
||||||
|
|
||||||
|
if(!await UserHelper.CanSeeUserPage(h.optionnalUserID, userID))
|
||||||
|
h.error(401, "You are not allowed to access this user posts !");
|
||||||
|
|
||||||
|
const posts = await PostsHelper.GetUserPosts(h.optionnalUserID, userID, startFrom);
|
||||||
|
|
||||||
|
let list = [];
|
||||||
|
for (const p of posts) {
|
||||||
|
list.push(await this.PostToAPI(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
h.send(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn a post object into an API entry
|
||||||
|
*
|
||||||
|
* @param p The post
|
||||||
|
*/
|
||||||
|
public static async PostToAPI(p: Post) : Promise<any> {
|
||||||
|
let data : any = {
|
||||||
|
ID: p.id,
|
||||||
|
useriD: p.userID,
|
||||||
|
user_page_id: p.userPageID,
|
||||||
|
group_id: p.groupID,
|
||||||
|
post_time: p.timeCreate,
|
||||||
|
content: p.hasContent ? p.content : null,
|
||||||
|
visibility_level: VISIBILITY_LEVELS_API[p.visibilityLevel],
|
||||||
|
kind: p.kind,
|
||||||
|
|
||||||
|
// File specific
|
||||||
|
file_size: !p.hasFile ? null : p.file.size,
|
||||||
|
file_type: !p.hasFile ? null : p.file.type,
|
||||||
|
file_path: !p.hasFile ? null : p.file.path,
|
||||||
|
file_url: !p.hasFile ? null : p.file.url
|
||||||
|
};
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import { WebAppControllers } from "./WebAppController";
|
|||||||
import { CallsController } from "./CallsController";
|
import { CallsController } from "./CallsController";
|
||||||
import { FriendsController } from "./FriendsController";
|
import { FriendsController } from "./FriendsController";
|
||||||
import { MoviesController } from "./MoviesController";
|
import { MoviesController } from "./MoviesController";
|
||||||
|
import { PostsController } from "./PostsController";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controllers routes
|
* Controllers routes
|
||||||
@ -182,6 +183,11 @@ export const Routes : Route[] = [
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Posts controller
|
||||||
|
{path: "/posts/get_user", cb: (h) => PostsController.GetListUser(h), needLogin: false},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Notifications controller
|
// Notifications controller
|
||||||
{path: "/notifications/count_unread", cb: (h) => NotificationsController.CountUnread(h)},
|
{path: "/notifications/count_unread", cb: (h) => NotificationsController.CountUnread(h)},
|
||||||
|
|
||||||
|
151
src/entities/Post.ts
Normal file
151
src/entities/Post.ts
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import { pathUserData } from "../utils/UserDataUtils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post entity
|
||||||
|
*
|
||||||
|
* @author Pierre HUBERT
|
||||||
|
*/
|
||||||
|
|
||||||
|
export enum PostVisibilityLevel {
|
||||||
|
//Posts that can be seen by anyone
|
||||||
|
VISIBILITY_PUBLIC = 1,
|
||||||
|
|
||||||
|
//Posts that can be seen by the friends of the user
|
||||||
|
VISIBILITY_FRIENDS = 2,
|
||||||
|
|
||||||
|
//Posts that can be seen by the user only
|
||||||
|
VISIBILITY_USER = 3,
|
||||||
|
|
||||||
|
//Posts that can be seen by the members of a group (same as friends)
|
||||||
|
VISIBILITY_GROUP_MEMBERS = 50,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum PostAccessLevel {
|
||||||
|
//When a user can't access to a post
|
||||||
|
NO_ACCESS = 0,
|
||||||
|
|
||||||
|
//When a user can see a post and perform basic actions such as liking
|
||||||
|
BASIC_ACCESS = 1,
|
||||||
|
|
||||||
|
//When a user has intermediate access to the post (delete post)
|
||||||
|
INTERMEDIATE_ACCESS = 2,
|
||||||
|
|
||||||
|
//When a user has a full access to the post
|
||||||
|
FULL_ACCESS = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum PostKind {
|
||||||
|
POST_KIND_TEXT = "text",
|
||||||
|
POST_KIND_IMAGE = "image",
|
||||||
|
POST_KIND_WEBLINK = "weblink",
|
||||||
|
POST_KIND_PDF = "pdf",
|
||||||
|
POST_KIND_MOVIE = "movie",
|
||||||
|
POST_KIND_COUNTDOWN = "countdown",
|
||||||
|
POST_KIND_SURVEY = "survey",
|
||||||
|
POST_KIND_YOUTUBE = "youtube",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum PostPageKind {
|
||||||
|
PAGE_KIND_USER = "user",
|
||||||
|
PAGE_KIND_GROUP = "group",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface PostFileBuilder {
|
||||||
|
path: string,
|
||||||
|
size: number,
|
||||||
|
type: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PostFile implements PostFileBuilder {
|
||||||
|
path: string;
|
||||||
|
size: number;
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
public constructor(info: PostFileBuilder) {
|
||||||
|
for (const key in info) {
|
||||||
|
if (info.hasOwnProperty(key))
|
||||||
|
this[key] = info[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get url() : string {
|
||||||
|
return pathUserData(this.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PostLinkBuilder {
|
||||||
|
url: string,
|
||||||
|
title: string,
|
||||||
|
description: string,
|
||||||
|
image: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PostLink implements PostLinkBuilder {
|
||||||
|
url: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
image: string;
|
||||||
|
|
||||||
|
public constructor(info: PostLinkBuilder) {
|
||||||
|
for (const key in info) {
|
||||||
|
if (info.hasOwnProperty(key))
|
||||||
|
this[key] = info[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface PostBuilder {
|
||||||
|
id: number,
|
||||||
|
userID: number,
|
||||||
|
timeCreate: number,
|
||||||
|
kindPage: PostPageKind,
|
||||||
|
pageID: number,
|
||||||
|
content: string,
|
||||||
|
visibilityLevel: PostVisibilityLevel,
|
||||||
|
kind: PostKind,
|
||||||
|
file ?: PostFile,
|
||||||
|
movieID ?: number,
|
||||||
|
timeEnd ?: number,
|
||||||
|
link ?: PostLink,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Post implements PostBuilder {
|
||||||
|
id: number;
|
||||||
|
userID: number;
|
||||||
|
timeCreate: number;
|
||||||
|
kindPage: PostPageKind;
|
||||||
|
pageID: number;
|
||||||
|
content: string;
|
||||||
|
visibilityLevel: PostVisibilityLevel;
|
||||||
|
kind: PostKind;
|
||||||
|
file?: PostFile;
|
||||||
|
movieID?: number;
|
||||||
|
timeEnd?: number;
|
||||||
|
link?: PostLink;
|
||||||
|
|
||||||
|
public constructor(info: PostBuilder) {
|
||||||
|
for (const key in info) {
|
||||||
|
if (info.hasOwnProperty(key))
|
||||||
|
this[key] = info[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get userPageID() : number {
|
||||||
|
return this.kindPage == PostPageKind.PAGE_KIND_USER ? this.pageID : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
get groupID() : number {
|
||||||
|
return this.kindPage == PostPageKind.PAGE_KIND_GROUP ? this.pageID : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasContent() : boolean {
|
||||||
|
return this.content != null && this.content && this.content.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasFile() : boolean {
|
||||||
|
return this.file != null && this.file != undefined;
|
||||||
|
}
|
||||||
|
}
|
162
src/helpers/PostsHelper.ts
Normal file
162
src/helpers/PostsHelper.ts
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import { PostKind, PostVisibilityLevel, Post, PostPageKind, PostFile, PostLink } from "../entities/Post";
|
||||||
|
import { FriendsHelper } from "./FriendsHelper";
|
||||||
|
import { DatabaseHelper } from "./DatabaseHelper";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posts helper
|
||||||
|
*
|
||||||
|
* @author Pierre HUBERT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table name
|
||||||
|
*/
|
||||||
|
const TABLE_NAME = "texte";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database mapping
|
||||||
|
*/
|
||||||
|
const PostDBTypes : Record<string, PostKind> = {
|
||||||
|
"texte": PostKind.POST_KIND_IMAGE,
|
||||||
|
"image": PostKind.POST_KIND_IMAGE,
|
||||||
|
"webpage_link": PostKind.POST_KIND_WEBLINK,
|
||||||
|
"pdf": PostKind.POST_KIND_PDF,
|
||||||
|
"video": PostKind.POST_KIND_MOVIE,
|
||||||
|
"count_down": PostKind.POST_KIND_COUNTDOWN,
|
||||||
|
"sondage": PostKind.POST_KIND_SURVEY,
|
||||||
|
"youtube": PostKind.POST_KIND_YOUTUBE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posts helper
|
||||||
|
*/
|
||||||
|
export class PostsHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the posts of a user
|
||||||
|
*
|
||||||
|
* @param userID The ID of the user making the request
|
||||||
|
* @param targetID The ID of the target user
|
||||||
|
* @param startFrom Start point (0 = none)
|
||||||
|
* @param limit Maximum number of messages to fetch
|
||||||
|
*/
|
||||||
|
public static async GetUserPosts(userID: number, targetID: number,
|
||||||
|
startFrom: number = 0, limit: number = 10) : Promise<Array<Post>> {
|
||||||
|
|
||||||
|
if(limit < 1)
|
||||||
|
throw Error("Limit of post query must be greater or equal to one!");
|
||||||
|
|
||||||
|
|
||||||
|
// Determine max user visibility
|
||||||
|
let level : PostVisibilityLevel = PostVisibilityLevel.VISIBILITY_PUBLIC;
|
||||||
|
|
||||||
|
if(userID == targetID)
|
||||||
|
level = PostVisibilityLevel.VISIBILITY_USER;
|
||||||
|
|
||||||
|
else if(userID > 0 && await FriendsHelper.AreFriend(userID, targetID))
|
||||||
|
level = PostVisibilityLevel.VISIBILITY_FRIENDS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Preprocess conditions
|
||||||
|
|
||||||
|
/// ============= PERMISSION CONDITIONS =================
|
||||||
|
// Visibility level
|
||||||
|
let customWhere = "((niveau_visibilite <= ?) ";
|
||||||
|
let customWhereArgs = [level.toString()];
|
||||||
|
|
||||||
|
// Add user post (if user signed in)
|
||||||
|
if(userID > 0) {
|
||||||
|
customWhere += " OR (ID_amis = ?) ";
|
||||||
|
customWhereArgs.push(userID.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
customWhere += ")"
|
||||||
|
/// ============= /PERMISSION CONDITIONS ================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ============== START POINT CONDITION =================
|
||||||
|
if(startFrom != 0) {
|
||||||
|
customWhere += " AND ID <= ?";
|
||||||
|
customWhereArgs.push(startFrom.toString());
|
||||||
|
}
|
||||||
|
// ============== /START POINT CONDITION ================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Perform the request
|
||||||
|
const entries = await DatabaseHelper.Query({
|
||||||
|
table: TABLE_NAME,
|
||||||
|
|
||||||
|
// Base conditions
|
||||||
|
where: {
|
||||||
|
ID_personne: targetID,
|
||||||
|
group_id: 0
|
||||||
|
},
|
||||||
|
|
||||||
|
customWhere: customWhere,
|
||||||
|
customWhereArgs: customWhereArgs,
|
||||||
|
|
||||||
|
order: "ID DESC",
|
||||||
|
limit: limit,
|
||||||
|
});
|
||||||
|
|
||||||
|
return entries.map((r) => this.DBToPost(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn a database entry into a row object
|
||||||
|
*
|
||||||
|
* @param row The database entry
|
||||||
|
*/
|
||||||
|
private static DBToPost(row: any) : Post {
|
||||||
|
|
||||||
|
const postPageKind = row.group_id == 0 ? PostPageKind.PAGE_KIND_USER : PostPageKind.PAGE_KIND_GROUP;
|
||||||
|
|
||||||
|
const postType = PostDBTypes[row.type];
|
||||||
|
|
||||||
|
return new Post({
|
||||||
|
// General info
|
||||||
|
id: row.ID,
|
||||||
|
userID: row.ID_amis == 0 ? row.ID_personne : row.ID_amis,
|
||||||
|
|
||||||
|
|
||||||
|
// Kind of target of the page and its ID
|
||||||
|
kindPage: postPageKind,
|
||||||
|
pageID: postPageKind == PostPageKind.PAGE_KIND_USER ? row.ID_personne : row.group_id,
|
||||||
|
|
||||||
|
// Basic info
|
||||||
|
timeCreate: row.time_insert == null ? (new Date(row.date_envoi).getTime() / 1000) : row.time_insert,
|
||||||
|
content: row.texte,
|
||||||
|
visibilityLevel: row.niveau_visibilite,
|
||||||
|
kind: postType,
|
||||||
|
|
||||||
|
// Files specific
|
||||||
|
file: row.path == null ? undefined : new PostFile({
|
||||||
|
size: Number(row.size),
|
||||||
|
type: row.file_type,
|
||||||
|
path: row.path
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Movies specific
|
||||||
|
movieID: row.idvideo == null ? undefined : row.idvideo,
|
||||||
|
|
||||||
|
// Coutdown timer specific
|
||||||
|
timeEnd: (row.time_end && row.time_end) > 0 ? row.time_end
|
||||||
|
|
||||||
|
// Coutdown legacy support
|
||||||
|
: (row.annee_fin && row.annee_fin > 2010 ? new Date(row.annee_fin + "/" + row.mois_fin + "/" + row.jour_fin).getTime() / 1000 : undefined),
|
||||||
|
|
||||||
|
|
||||||
|
// Weblink - specific
|
||||||
|
link: row.url_page == null ? undefined :
|
||||||
|
new PostLink({
|
||||||
|
url: row.url_page,
|
||||||
|
title: row.titre_page,
|
||||||
|
description: row.description_page,
|
||||||
|
image: row.image_page
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user