mirror of
https://gitlab.com/comunic/comunicapiv2
synced 2024-12-28 14:38:52 +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 { FriendsController } from "./FriendsController";
|
||||
import { MoviesController } from "./MoviesController";
|
||||
import { PostsController } from "./PostsController";
|
||||
|
||||
/**
|
||||
* 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
|
||||
{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