2020-01-03 15:38:44 +00:00
|
|
|
import { PostKind, PostVisibilityLevel, Post, PostPageKind, PostFile, PostLink, PostAccessLevel } from "../entities/Post";
|
2020-01-03 09:17:34 +00:00
|
|
|
import { FriendsHelper } from "./FriendsHelper";
|
|
|
|
import { DatabaseHelper } from "./DatabaseHelper";
|
2020-01-03 15:38:44 +00:00
|
|
|
import { UserHelper } from "./UserHelper";
|
2020-01-03 15:49:11 +00:00
|
|
|
import { GroupsHelper } from "./GroupsHelper";
|
|
|
|
import { GroupMembershipLevels } from "../entities/GroupMember";
|
2020-01-03 09:17:34 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Posts helper
|
|
|
|
*
|
|
|
|
* @author Pierre HUBERT
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Table name
|
|
|
|
*/
|
|
|
|
const TABLE_NAME = "texte";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Database mapping
|
|
|
|
*/
|
|
|
|
const PostDBTypes : Record<string, PostKind> = {
|
2020-01-03 16:38:30 +00:00
|
|
|
"texte": PostKind.POST_KIND_TEXT,
|
2020-01-03 09:17:34 +00:00
|
|
|
"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));
|
|
|
|
}
|
|
|
|
|
2020-01-04 09:27:54 +00:00
|
|
|
/**
|
|
|
|
* Get the posts of a group
|
|
|
|
*
|
|
|
|
* @param userID The ID of the user making the request
|
|
|
|
* @param groupID The ID of the target group
|
|
|
|
* @param startFrom Start point. 0 for none
|
|
|
|
*/
|
|
|
|
public static async GetGroupPosts(userID: number, groupID: number,
|
|
|
|
startFrom: number = 0, limit: number = 10) : Promise<Array<Post>> {
|
|
|
|
|
|
|
|
if(limit < 1)
|
|
|
|
throw new Error("Limit (" + limit +") is invalid!");
|
|
|
|
|
|
|
|
// Check membership of the user
|
|
|
|
const membership = await GroupsHelper.GetMembershipLevel(groupID, userID);
|
|
|
|
const canSeeAllPosts = membership <= GroupMembershipLevels.MEMBER;
|
|
|
|
|
|
|
|
const visibilityLevel = canSeeAllPosts ? PostVisibilityLevel.VISIBILITY_GROUP_MEMBERS : PostVisibilityLevel.VISIBILITY_PUBLIC;
|
|
|
|
|
|
|
|
|
|
|
|
// Prepare request
|
|
|
|
|
|
|
|
// === VISIBILITY RESTRICTION ===
|
|
|
|
let customWhere = "(niveau_visibilite <= ?)";
|
|
|
|
let customWhereArgs = [visibilityLevel.toString()];
|
|
|
|
// == /VISIBILITY RESTRICTION ===
|
|
|
|
|
|
|
|
|
|
|
|
// === START POINT ===
|
|
|
|
if(startFrom != 0) {
|
|
|
|
customWhere += " AND ID <= ?";
|
|
|
|
customWhereArgs.push(startFrom.toString());
|
|
|
|
}
|
|
|
|
// == /START POINT ===
|
|
|
|
|
|
|
|
|
|
|
|
const results = await DatabaseHelper.Query({
|
|
|
|
table: TABLE_NAME,
|
|
|
|
where: {
|
|
|
|
group_id: groupID
|
|
|
|
},
|
|
|
|
customWhere: customWhere,
|
|
|
|
customWhereArgs: customWhereArgs,
|
2020-01-04 10:30:33 +00:00
|
|
|
order: "ID DESC",
|
|
|
|
limit: limit
|
|
|
|
});
|
|
|
|
|
|
|
|
return results.map((r) => this.DBToPost(r));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the latest posts of a user
|
|
|
|
*
|
|
|
|
* @param userID The ID of the user making the request
|
|
|
|
* @param startFrom Startpoint for the research
|
|
|
|
* @param limit Limit of the research (default: 10)
|
|
|
|
* @param includeGroups Specify whether groups can be selected too or not
|
|
|
|
*/
|
|
|
|
public static async GetLatest(userID: number, startFrom: number = 10,
|
|
|
|
limit: number = 10, includeGroups: boolean = false) {
|
|
|
|
|
|
|
|
if(limit < 1)
|
|
|
|
throw new Error("Limit of the query must be greater than 0!");
|
|
|
|
|
|
|
|
const visibilityLevel = PostVisibilityLevel.VISIBILITY_FRIENDS;
|
|
|
|
|
|
|
|
// Get the list of friends of the user
|
|
|
|
const friendsList = await FriendsHelper.GetList(userID, true);
|
|
|
|
|
|
|
|
// Prepare the request on the database
|
|
|
|
|
|
|
|
// === Membership condition ===
|
|
|
|
let customWhere = "(";
|
|
|
|
|
|
|
|
// === FRIENDS POSTS ===
|
|
|
|
customWhere += "(group_id = 0 AND niveau_visibilite <= ? AND (ID_personne = ?";
|
|
|
|
let customWhereArgs = [visibilityLevel.toString(), userID.toString()];
|
|
|
|
|
|
|
|
friendsList.forEach((f) => {
|
|
|
|
customWhere += " OR ID_personne = ?";
|
|
|
|
customWhereArgs.push(f.friendID.toString());
|
|
|
|
});
|
|
|
|
|
|
|
|
customWhere += "))"
|
|
|
|
// === FRIENDS POSTS ===
|
|
|
|
|
|
|
|
|
|
|
|
// === GROUPS POSTS ===
|
|
|
|
if(includeGroups) {
|
|
|
|
|
|
|
|
const groups = await GroupsHelper.GetListUser(userID, true);
|
|
|
|
|
|
|
|
groups.forEach((groupID) => {
|
|
|
|
customWhere += " OR group_id = ? ";
|
|
|
|
customWhereArgs.push(groupID.toString());
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
// == /GROUPS POSTS ===
|
|
|
|
|
|
|
|
customWhere += ")";
|
|
|
|
// === /Membership condition ===
|
|
|
|
|
|
|
|
|
|
|
|
// === START POINT ===
|
|
|
|
if(startFrom > 0) {
|
|
|
|
customWhere += "AND ID <= ?";
|
|
|
|
customWhereArgs.push(startFrom.toString());
|
|
|
|
}
|
|
|
|
// == /START POINT ===
|
|
|
|
|
|
|
|
const results = await DatabaseHelper.Query({
|
|
|
|
table: TABLE_NAME,
|
|
|
|
customWhere: customWhere,
|
|
|
|
customWhereArgs: customWhereArgs,
|
2020-01-04 09:27:54 +00:00
|
|
|
order: "ID DESC",
|
|
|
|
limit: limit
|
|
|
|
});
|
|
|
|
|
|
|
|
return results.map((r) => this.DBToPost(r));
|
|
|
|
}
|
|
|
|
|
2020-01-04 11:04:14 +00:00
|
|
|
/**
|
|
|
|
* Get information about a single post
|
|
|
|
*
|
|
|
|
* @param postID Target post ID
|
|
|
|
*/
|
|
|
|
public static async GetSingle(postID: number) : Promise<Post> {
|
|
|
|
const row = await DatabaseHelper.QueryRow({
|
|
|
|
table: TABLE_NAME,
|
|
|
|
where: {
|
|
|
|
ID: postID
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if(row == null)
|
|
|
|
throw new Error("Post " + postID + " not found!");
|
|
|
|
|
|
|
|
return this.DBToPost(row);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the access level of a user over a post
|
|
|
|
*
|
|
|
|
* This is a convenience function
|
|
|
|
*
|
|
|
|
* @param userID Target user ID
|
|
|
|
* @param postID Target post ID
|
|
|
|
*/
|
|
|
|
public static async GetAccessLevelFromPostID(userID: number, postID: number) : Promise<PostAccessLevel> {
|
|
|
|
return await this.GetAccessLevel(userID, await this.GetSingle(postID));
|
|
|
|
}
|
|
|
|
|
2020-01-03 15:38:44 +00:00
|
|
|
/**
|
|
|
|
* Get the access level of a user over a post
|
|
|
|
*
|
|
|
|
* @param userID Target user ID
|
|
|
|
* @param post Target post
|
|
|
|
*/
|
|
|
|
public static async GetAccessLevel(userID: number, post: Post) : Promise<PostAccessLevel> {
|
|
|
|
|
|
|
|
// User is the owner of the post
|
|
|
|
if(userID == post.userID)
|
|
|
|
return PostAccessLevel.FULL_ACCESS;
|
|
|
|
|
|
|
|
|
|
|
|
// User page
|
|
|
|
if(post.kindPage == PostPageKind.PAGE_KIND_USER) {
|
|
|
|
|
|
|
|
// Post made on user page
|
|
|
|
if(post.pageID == userID)
|
|
|
|
return PostAccessLevel.INTERMEDIATE_ACCESS;
|
|
|
|
|
|
|
|
// Check if the post is private
|
|
|
|
if(post.visibilityLevel == PostVisibilityLevel.VISIBILITY_USER)
|
|
|
|
return PostAccessLevel.NO_ACCESS;
|
|
|
|
|
|
|
|
// In case the post is only for friends
|
|
|
|
else if(post.visibilityLevel == PostVisibilityLevel.VISIBILITY_FRIENDS) {
|
|
|
|
|
|
|
|
if(userID < 1 /* user not signed in */
|
|
|
|
|| !await FriendsHelper.AreFriend(userID, post.pageID) /* not a friend */)
|
|
|
|
return PostAccessLevel.NO_ACCESS;
|
|
|
|
|
|
|
|
else
|
|
|
|
return PostAccessLevel.BASIC_ACCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// In case of public post
|
|
|
|
else if(post.visibilityLevel == PostVisibilityLevel.VISIBILITY_PUBLIC) {
|
|
|
|
|
|
|
|
// Check if the user can see the page
|
|
|
|
if(await UserHelper.CanSeeUserPage(userID, post.userPageID))
|
|
|
|
return PostAccessLevel.BASIC_ACCESS;
|
|
|
|
|
|
|
|
// Else no access to the user
|
|
|
|
return PostAccessLevel.NO_ACCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Group page
|
|
|
|
else if(post.kindPage == PostPageKind.PAGE_KIND_GROUP) {
|
2020-01-03 15:49:11 +00:00
|
|
|
// TODO : check this code
|
|
|
|
|
2020-01-04 09:29:42 +00:00
|
|
|
const accessLevel = await GroupsHelper.GetMembershipLevel(post.groupID, userID);
|
2020-01-03 15:38:44 +00:00
|
|
|
|
2020-01-03 15:49:11 +00:00
|
|
|
// Moderator & admin = intermediate access
|
|
|
|
if(accessLevel < GroupMembershipLevels.MEMBER)
|
|
|
|
return PostAccessLevel.INTERMEDIATE_ACCESS;
|
|
|
|
|
|
|
|
// Members can see all the posts of a group
|
|
|
|
if(accessLevel == GroupMembershipLevels.MEMBER)
|
|
|
|
return PostAccessLevel.BASIC_ACCESS;
|
|
|
|
|
|
|
|
// Now we check if the post is public & the group is open
|
|
|
|
if(post.visibilityLevel != PostVisibilityLevel.VISIBILITY_PUBLIC
|
|
|
|
|| !await GroupsHelper.IsOpen(post.groupID))
|
|
|
|
return PostAccessLevel.NO_ACCESS;
|
|
|
|
|
|
|
|
// Public post + open group = basic access
|
|
|
|
return PostAccessLevel.BASIC_ACCESS;
|
2020-01-03 15:38:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
throw Error("GetAccessLevel reached an unimplemented status!");
|
|
|
|
}
|
|
|
|
|
2020-01-03 16:01:09 +00:00
|
|
|
/**
|
|
|
|
* Check out whether comments are allowed on a post or not
|
|
|
|
*
|
|
|
|
* @param post The post to check
|
|
|
|
*/
|
|
|
|
public static async AllowCommentsOnPost(post: Post) : Promise<boolean> {
|
|
|
|
return !post.isUserPage || await UserHelper.AllowComments(post.userPageID);
|
|
|
|
}
|
|
|
|
|
2020-01-04 11:04:14 +00:00
|
|
|
/**
|
|
|
|
* Check out whether a post exists or not
|
|
|
|
*
|
|
|
|
* @param postID The id of the post to check
|
|
|
|
*/
|
|
|
|
public static async Exists(postID: number) : Promise<boolean> {
|
|
|
|
return await DatabaseHelper.Count({
|
|
|
|
table: TABLE_NAME,
|
|
|
|
where: {
|
|
|
|
ID: postID
|
|
|
|
}
|
|
|
|
}) > 0;
|
|
|
|
}
|
|
|
|
|
2020-01-03 09:17:34 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|