import 'package:comunic/enums/post_kind.dart'; import 'package:comunic/enums/post_target.dart'; import 'package:comunic/enums/post_visibility_level.dart'; import 'package:comunic/enums/user_access_levels.dart'; import 'package:comunic/helpers/comments_helper.dart'; import 'package:comunic/helpers/survey_helper.dart'; import 'package:comunic/helpers/websocket_helper.dart'; import 'package:comunic/lists/comments_list.dart'; import 'package:comunic/lists/posts_list.dart'; import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/displayed_content.dart'; import 'package:comunic/models/new_post.dart'; import 'package:comunic/models/post.dart'; import 'package:http_parser/http_parser.dart'; /// Posts helper /// /// @author Pierre HUBERT const _APIPostsVisibilityLevelMap = { "public": PostVisibilityLevel.PUBLIC, "friends": PostVisibilityLevel.FRIENDS, "private": PostVisibilityLevel.USER, "members": PostVisibilityLevel.GROUP_MEMBERS }; const _APIPostsKindsMap = { "text": PostKind.TEXT, "image": PostKind.IMAGE, "weblink": PostKind.WEB_LINK, "pdf": PostKind.PDF, "countdown": PostKind.COUNTDOWN, "survey": PostKind.SURVEY, "youtube": PostKind.YOUTUBE }; const _APIUserAccessMap = { "no-access": UserAccessLevels.NONE, "basic": UserAccessLevels.BASIC, "intermediate": UserAccessLevels.INTERMEDIATE, "full": UserAccessLevels.FULL }; const _APIPostsTargetKindsMap = { PostTarget.USER_PAGE: "user", PostTarget.GROUP_PAGE: "group" }; class PostsHelper { /// Stores the list of posts we are registered to /// /// First int = post ID /// Second int = number of registered people static final _registeredPosts = Map(); /// Get the list of latest posts. Return the list of posts or null in case of /// failure Future getLatest({int from = 0}) async { final response = await APIRequest(uri: "posts/get_latest", needLogin: true, args: { "include_groups": true.toString(), "startFrom": from.toString(), }).exec(); if (response.code != 200) return null; try { // Parse & return the list of posts return PostsList() ..addAll(response.getArray()!.map((f) => _apiToPost(f))); } catch (e) { print(e.toString()); return null; } } /// Get the list of posts of a user Future getUserPosts(int? userID, {int from = 0}) async { final response = await (APIRequest(uri: "posts/get_user", needLogin: true) ..addInt("userID", userID) ..addInt("startFrom", from == 0 ? 0 : from - 1)) .exec(); if (response.code != 200) return null; try { // Parse & return the list of posts return PostsList() ..addAll(response.getArray()!.map((f) => _apiToPost(f))); } catch (e) { print(e.toString()); return null; } } /// Get the list of posts of a group Future getGroupPosts(int groupID, {int from = 0}) async { final response = await (APIRequest(uri: "posts/get_group", needLogin: true) ..addInt("groupID", groupID) ..addInt("startFrom", from == 0 ? 0 : from - 1)) .exec(); if (response.code != 200) return null; try { // Parse & return the list of posts return PostsList() ..addAll(response.getArray()!.map((f) => _apiToPost(f))); } catch (e) { print(e.toString()); return null; } } /// Get a single post information Future getSingle(int postID) async { final response = await APIRequest( uri: "posts/get_single", args: {"postID": postID.toString()}, needLogin: true, ).exec(); if (!response.isOK) throw Exception("Could not get information about the post!"); return _apiToPost(response.getObject()); } /// Create a new post /// /// This function crash in case of error Future createPost(NewPost post) async { APIRequest request = APIRequest(uri: "posts/create", needLogin: true, args: { "kind-page": _APIPostsTargetKindsMap[post.target], "kind-id": post.targetID.toString(), "visibility": _APIPostsVisibilityLevelMap.map( (s, v) => MapEntry(v, s))[post.visibility], "kind": _APIPostsKindsMap.map((s, k) => MapEntry(k, s))[post.kind], "content": post.content }); switch (post.kind) { case PostKind.TEXT: break; case PostKind.IMAGE: request.addBytesFile("image", post.image); break; case PostKind.WEB_LINK: request.addString("url", post.url); break; case PostKind.PDF: request.addBytesFile( "pdf", BytesFile("file.pdf", post.pdf, type: MediaType.parse("application/pdf"))); break; case PostKind.COUNTDOWN: request.addInt( "time-end", (post.timeEnd!.millisecondsSinceEpoch / 1000).floor()); break; case PostKind.SURVEY: request.addString("question", post.survey!.question); request.addString("answers", post.survey!.answers.join("<>")); request.addBool( "allowNewAnswers", post.survey!.allowNewChoicesCreation); break; case PostKind.YOUTUBE: request.addString("youtube_id", post.youtubeId); break; default: throw Exception("Unsupported post type :" + post.kind.toString()); } final response = await request.execWithFiles(); if (!response.isOK) throw Exception("Could not create the post !"); } /// Update a post content Future updateContent(int id, String newContent) async { return (await APIRequest( uri: "posts/update_content", needLogin: true, args: { "postID": id.toString(), "new_content": newContent, }, ).exec()) .isOK; } /// Update a post visibility Future setVisibility(int id, PostVisibilityLevel level) async { return (await APIRequest( uri: "posts/set_visibility_level", needLogin: true, args: { "postID": id.toString(), "new_level": _APIPostsVisibilityLevelMap.map((k, v) => MapEntry(v, k))[level] }, ).exec()) .isOK; } /// Delete a post Future delete(int id) async { return (await APIRequest( uri: "posts/delete", needLogin: true, args: {"postID": id.toString()}, ).exec()) .isOK; } /// Register to a post events Future registerPostEvents(int id) async { if (_registeredPosts.containsKey(id)) _registeredPosts.update(id, (v) => v + 1); else { _registeredPosts[id] = 1; await ws("\$main/register_post", {"postID": id}); } } /// Un-register to post events Future unregisterPostEvents(int id) async { if (!_registeredPosts.containsKey(id)) return; _registeredPosts.update(id, (v) => v - 1); if (_registeredPosts[id]! <= 0) { _registeredPosts.remove(id); await ws("\$main/unregister_post", {"postID": id}); } } /// Turn an API entry into a [Post] object Post _apiToPost(Map map) { final postKind = _APIPostsKindsMap[map["kind"]]!; // Parse comments CommentsList? comments; if (map["comments"] != null) { comments = CommentsList(); map["comments"] .forEach((v) => comments!.add(CommentsHelper.apiToComment(v))); } final survey = postKind == PostKind.SURVEY ? SurveyHelper.apiToSurvey(map["data_survey"]) : null; return Post( id: map["ID"], userID: map["userID"], userPageID: map["user_page_id"], groupID: map["group_id"], timeSent: map["post_time"], content: DisplayedString(map["content"]), visibilityLevel: _APIPostsVisibilityLevelMap[map["visibility_level"]]!, kind: postKind, fileSize: map["file_size"], fileType: map["file_type"], filePath: map["file_path"], fileURL: map["file_path_url"], timeEnd: map["time_end"], linkURL: map["link_url"], linkTitle: map["link_title"], linkDescription: map["link_description"], linkImage: map["link_image"], likes: map["likes"], userLike: map["userlike"], access: _APIUserAccessMap[map["user_access"]]!, comments: comments, survey: survey); } }