1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-24 22:09:21 +00:00
comunicmobile/lib/helpers/groups_helper.dart
2022-03-11 16:27:01 +01:00

424 lines
14 KiB
Dart

import 'dart:typed_data';
import 'package:comunic/helpers/conversations_helper.dart';
import 'package:comunic/lists/group_members_list.dart';
import 'package:comunic/lists/groups_list.dart';
import 'package:comunic/models/advanced_group_info.dart';
import 'package:comunic/models/api_request.dart';
import 'package:comunic/models/conversation.dart';
import 'package:comunic/models/group.dart';
import 'package:comunic/models/group_membership.dart';
import 'package:comunic/models/new_group_conversation.dart';
import 'package:comunic/utils/api_utils.dart';
import 'package:comunic/utils/map_utils.dart';
/// Groups helper
///
/// @author Pierre HUBERT
const APIGroupsMembershipLevelsMap = {
"administrator": GroupMembershipLevel.ADMINISTRATOR,
"moderator": GroupMembershipLevel.MODERATOR,
"member": GroupMembershipLevel.MEMBER,
"invited": GroupMembershipLevel.INVITED,
"pending": GroupMembershipLevel.PENDING,
"visitor": GroupMembershipLevel.VISITOR
};
const _APIGroupsVisibilityLevelsMap = {
"open": GroupVisibilityLevel.OPEN,
"private": GroupVisibilityLevel.PRIVATE,
"secrete": GroupVisibilityLevel.SECRETE
};
const _APIGroupsRegistrationLevelsMap = {
"open": GroupRegistrationLevel.OPEN,
"moderated": GroupRegistrationLevel.MODERATED,
"closed": GroupRegistrationLevel.CLOSED
};
const _APIGroupsPostsCreationLevelsMap = {
"moderators": GroupPostCreationLevel.MODERATORS,
"members": GroupPostCreationLevel.MEMBERS
};
final _groupsListCache = GroupsList();
/// Callback for getting advanced user information
enum GetAdvancedInfoStatus { SUCCESS, ACCESS_DENIED }
class GetAdvancedInfoResult {
final GetAdvancedInfoStatus status;
final AdvancedGroupInfo? info;
GetAdvancedInfoResult(this.status, this.info);
}
/// Groups helper
class GroupsHelper {
/// Download a list of groups information from the server
Future<GroupsList?> _downloadList(Set<int?> groups) async {
final response = await APIRequest(
uri: "groups/get_multiple_info",
needLogin: true,
args: {"list": groups.join(",")},
).exec();
if (response.code != 200) return null;
final list = GroupsList();
response
.getObject()
.forEach((k, d) => list[int.parse(k)] = getGroupFromAPI(d));
return list;
}
/// Get a list of groups from the server. In case of error, this method throws
/// an exception
Future<GroupsList> getListOrThrow(Set<int?> groups,
{bool force = false}) async {
final list = await getList(groups, force: force);
if (list == null) throw Exception("Could not get the list of groups!");
return list;
}
/// Get a list of groups from the server
Future<GroupsList?> getList(Set<int?> groups, {bool force = false}) async {
final list = GroupsList();
// Check which groups information to download
final toDownload = Set<int?>();
groups.forEach((groupID) {
if (!force && _groupsListCache.containsKey(groupID))
list[groupID] = _groupsListCache[groupID];
else
toDownload.add(groupID);
});
// Download required groups information
if (toDownload.length > 0) {
final downloaded = await _downloadList(toDownload);
if (downloaded == null) return null;
list.addAll(downloaded);
_groupsListCache.addAll(downloaded);
}
return list;
}
/// Get information about a single group
///
/// Throws in case of failure
Future<Group> getSingle(int groupID, {bool force = false}) async {
return (await getListOrThrow(Set<int>()..add(groupID), force: force))
.values
.first;
}
/// Get the list of groups of a user
Future<Set<int?>> getListUser() async =>
(await APIRequest(uri: "groups/get_my_list", needLogin: true).exec())
.assertOk()
.getArray()!
.map((f) => cast<int>(f))
.toSet();
/// Create a new group
///
/// Throws in case of failure
static Future<int> create(String name) async {
final result = await APIRequest.withLogin("groups/create")
.addString("name", name)
.execWithThrow();
return result.getObject()["id"];
}
/// Perform a simple membership request
static Future<bool> _simpleMembershipRequest(int groupID, String uri,
{Map<String, String>? args}) async =>
(await (APIRequest.withLogin(uri)
..addInt("id", groupID)
..addArgs(args == null ? Map() : args))
.exec())
.isOK;
/// Remove group membership
Future<bool> removeMembership(int groupID) async =>
_simpleMembershipRequest(groupID, "groups/remove_membership");
/// Cancel membership request
Future<bool> cancelRequest(int groupID) async =>
_simpleMembershipRequest(groupID, "groups/cancel_request");
/// Send a new membership request
static Future<bool> sendRequest(int groupID) async =>
_simpleMembershipRequest(groupID, "groups/send_request");
/// Respond to a group membership invitation
static Future<bool> respondInvitation(int groupID, bool accept) async =>
_simpleMembershipRequest(groupID, "groups/respond_invitation", args: {
"accept": accept ? "true" : "false",
});
/// Update group following status
Future<bool> setFollowing(int groupID, bool follow) async =>
(await (APIRequest(uri: "groups/set_following", needLogin: true)
..addInt("groupID", groupID)
..addBool("follow", follow))
.exec())
.isOK;
/// Get advanced information about the user
Future<GetAdvancedInfoResult> getAdvancedInfo(int? groupID) async {
// Get advanced information about the user
final result =
await (APIRequest(uri: "groups/get_advanced_info", needLogin: true)
..addInt("id", groupID))
.exec();
switch (result.code) {
case 401:
return GetAdvancedInfoResult(GetAdvancedInfoStatus.ACCESS_DENIED, null);
case 200:
return GetAdvancedInfoResult(GetAdvancedInfoStatus.SUCCESS,
_getAdvancedGroupInfoFromAPI(result.getObject()));
default:
throw Exception("Could not get advanced group information!");
}
}
/// Get group settings
///
/// This function is currently a kind of alias, but it might
/// change in the future
///
/// Throws in case of error
Future<AdvancedGroupInfo?> getSettings(int groupID) async {
final groupInfo = await getAdvancedInfo(groupID);
if (groupInfo.status != GetAdvancedInfoStatus.SUCCESS)
throw Exception("Could not get group information!");
return groupInfo.info;
}
/// Check the availability of a virtual directory
///
/// Throws in case of error
static Future<void> checkVirtualDirectoryAvailability(
int groupID, String dir) async =>
await APIRequest(uri: "groups/checkVirtualDirectory", needLogin: true)
.addInt("groupID", groupID)
.addString("directory", dir)
.execWithThrow();
/// Update (set) new group settings
///
/// Throws in case of error
static Future<void> setSettings(AdvancedGroupInfo settings) async {
await APIRequest(uri: "groups/set_settings", needLogin: true)
.addInt("id", settings.id)
.addString("name", settings.name)
.addString("virtual_directory", settings.virtualDirectory)
.addString("visibility",
invertMap(_APIGroupsVisibilityLevelsMap)[settings.visibilityLevel])
.addString(
"registration_level",
invertMap(
_APIGroupsRegistrationLevelsMap)[settings.registrationLevel])
.addString(
"posts_level",
invertMap(
_APIGroupsPostsCreationLevelsMap)[settings.postCreationLevel])
.addBool("is_members_list_public", settings.isMembersListPublic!)
.addString("description", settings.description)
.addString("url", settings.url)
.execWithThrow();
}
/// Upload a new logo
///
/// Throws in case of failure
static Future<void> uploadNewLogo(int groupID, Uint8List? bytes) async =>
await APIRequest(uri: "groups/upload_logo", needLogin: true)
.addInt("id", groupID)
.addBytesFile("logo", BytesFile("logo.png", bytes))
.execWithFilesAndThrow();
/// Delete group logo
///
/// Throws in case of error
static Future<void> deleteLogo(int groupID) async =>
await APIRequest(uri: "groups/delete_logo", needLogin: true)
.addInt("id", groupID)
.execWithThrow();
/// Delete a group
///
/// Throws in case of error
static Future<void> deleteGroup(int groupID, String password) async =>
await APIRequest(uri: "groups/delete", needLogin: true)
.addInt("groupID", groupID)
.addString("password", password)
.execWithThrow();
/// Get the list of members of the group
///
/// Throws in case of failure
static Future<GroupMembersList> getMembersList(int groupID) async =>
GroupMembersList()
..addAll((await APIRequest(uri: "groups/get_members", needLogin: true)
.addInt("id", groupID)
.execWithThrow())
.getArray()!
.map((f) => _apiToGroupMembership(f))
.toList());
/// Invite a user to join a group
///
/// Throws an exception in case of failure
static Future<void> sendInvitation(int groupID, int userID) async =>
APIRequest.withLogin("groups/invite")
.addInt("group_id", groupID)
.addInt("userID", userID)
.execWithThrow();
/// Cancel a group membership invitation
///
/// Throws an exception in case of failure
static Future<void> cancelInvitation(int groupID, int? userID) async =>
await APIRequest.withLogin("groups/cancel_invitation")
.addInt("groupID", groupID)
.addInt("userID", userID)
.execWithThrow();
/// Respond to a group membership request
///
/// Throws an exception in case of failure
static Future<void> respondRequest(
int groupID, int? userID, bool accept) async =>
await APIRequest.withLogin("groups/respond_request")
.addInt("groupID", groupID)
.addInt("userID", userID)
.addBool("accept", accept)
.execWithThrow();
/// Remove a member from a group
///
/// Throws an exception in case of failure
static Future<void> removeMemberFromGroup(int groupID, int userID) async =>
APIRequest.withLogin("groups/delete_member")
.addInt("groupID", groupID)
.addInt("userID", userID)
.execWithThrow();
/// Change the membership level of a member of a group
///
/// Throws an exception in case of failure
static Future<void> setNewLevel(
int groupID, int userID, GroupMembershipLevel level) async =>
await APIRequest.withLogin("groups/update_membership_level")
.addInt("groupID", groupID)
.addInt("userID", userID)
.addString("level", invertMap(APIGroupsMembershipLevelsMap)[level])
.execWithThrow();
/// Create a new group conversation
///
/// Throws in case of failure
static Future<void> createGroupConversation(
NewGroupConversation conv) async =>
await APIRequest.withLogin("groups/create_conversation")
.addInt("group_id", conv.groupID)
.addString(
"min_membership_level",
APIGroupsMembershipLevelsMap.entries
.firstWhere((e) => e.value == conv.minMembershipLevel)
.key)
.addString("name", conv.name)
.execWithThrow();
/// Set new conversation visibility level
///
/// Throws in case of failure
static Future<void> setConversationVisibility(
int? convID, GroupMembershipLevel? newLevel) async =>
await APIRequest.withLogin("groups/set_conversation_visibility")
.addInt("conv_id", convID)
.addString(
"min_membership_level",
APIGroupsMembershipLevelsMap.entries
.firstWhere((e) => e.value == newLevel)
.key)
.execWithThrow();
/// Delete a group's conversation
///
/// Throws in case of failure
static Future<void> deleteConversation(int? convID) async =>
await APIRequest.withLogin("groups/delete_conversation")
.addInt("conv_id", convID)
.execWithThrow();
/// Turn an API entry into a group object
static Group getGroupFromAPI(Map<String, dynamic> map) {
return Group(
id: map["id"],
name: map["name"],
iconURL: map["icon_url"],
numberMembers: map["number_members"],
membershipLevel: APIGroupsMembershipLevelsMap[map["membership"]]!,
visibilityLevel: _APIGroupsVisibilityLevelsMap[map["visibility"]]!,
registrationLevel:
_APIGroupsRegistrationLevelsMap[map["registration_level"]]!,
postCreationLevel: _APIGroupsPostsCreationLevelsMap[map["posts_level"]]!,
virtualDirectory: nullToEmpty(map["virtual_directory"]),
following: map["following"]);
}
/// Get advanced group information
AdvancedGroupInfo _getAdvancedGroupInfoFromAPI(Map<String, dynamic> map) =>
AdvancedGroupInfo(
id: map["id"],
name: map["name"],
iconURL: map["icon_url"],
numberMembers: map["number_members"],
membershipLevel: APIGroupsMembershipLevelsMap[map["membership"]]!,
visibilityLevel: _APIGroupsVisibilityLevelsMap[map["visibility"]]!,
registrationLevel:
_APIGroupsRegistrationLevelsMap[map["registration_level"]]!,
postCreationLevel: _APIGroupsPostsCreationLevelsMap[map["posts_level"]]!,
isMembersListPublic: map["is_members_list_public"],
virtualDirectory: nullToEmpty(map["virtual_directory"]),
following: map["following"],
timeCreate: map["time_create"],
description: nullToEmpty(map["description"]),
url: nullToEmpty(map["url"]),
likes: map["number_likes"],
userLike: map["is_liking"],
conversations: map["conversations"]
.map((s) => ConversationsHelper.apiToConversation(s))
.cast<Conversation>()
.toList(),
isForezGroup: map["is_forez_group"],
);
/// Create [GroupMembership] object from API entry
static GroupMembership _apiToGroupMembership(Map<String, dynamic> row) =>
GroupMembership(
userID: row["user_id"],
groupID: row["group_id"],
timeCreate: row["time_create"],
level: APIGroupsMembershipLevelsMap[row["level"]]!,
);
}