diff --git a/lib/src/Event.dart b/lib/src/Event.dart index de6014e..88904a7 100644 --- a/lib/src/Event.dart +++ b/lib/src/Event.dart @@ -25,6 +25,7 @@ import 'dart:convert'; import 'package:famedlysdk/src/utils/ChatTime.dart'; import 'package:famedlysdk/src/Client.dart'; import './User.dart'; +import './Room.dart'; /// A single Matrix event, e.g. a message in a chat. class Event { @@ -77,7 +78,7 @@ class Event { } - static Event fromJson(Map jsonObj) { + static Event fromJson(Map jsonObj, Room room) { Map content; try { content = json.decode(jsonObj["content_json"]); @@ -87,7 +88,7 @@ class Event { } return Event( jsonObj["id"], - User.fromJson(jsonObj), + User.fromJson(jsonObj, room), ChatTime(jsonObj["origin_server_ts"]), stateKey: User(jsonObj["state_key"]), environment: jsonObj["type"], @@ -97,7 +98,7 @@ class Event { ); } - static Future> getEventList(Client matrix, String roomID) async{ + static Future> getEventList(Client matrix, Room room) async{ List> eventRes = await matrix.store.db.rawQuery( "SELECT * " + " FROM Events events, Participants participants " + @@ -105,12 +106,12 @@ class Event { " AND events.sender=participants.matrix_id " + " GROUP BY events.id " + " ORDER BY origin_server_ts DESC", - [roomID]); + [room.id]); List eventList = []; for (num i = 0; i < eventRes.length; i++) - eventList.add(Event.fromJson(eventRes[i])); + eventList.add(Event.fromJson(eventRes[i], room)); return eventList; } diff --git a/lib/src/Room.dart b/lib/src/Room.dart index c051908..3ffe5c9 100644 --- a/lib/src/Room.dart +++ b/lib/src/Room.dart @@ -287,7 +287,7 @@ class Room { /// Load all events for a given room from the store. This includes all /// senders of those events, who will be added to the participants list. Future> loadEvents() async { - this.events = await client.store.getEventList(id); + this.events = await client.store.getEventList(this); Map participantMap = {}; for (num i = 0; i < events.length; i++) { @@ -302,7 +302,7 @@ class Room { /// Load all participants for a given room from the store. Future> loadParticipants() async { - this.participants = await client.store.loadParticipants(id); + this.participants = await client.store.loadParticipants(this); return this.participants; } @@ -319,11 +319,11 @@ class Room { for (num i = 0; i < res["chunk"].length; i++) { User newUser = User(res["chunk"][i]["state_key"], displayName: res["chunk"][i]["content"]["displayname"] ?? "", - status: res["chunk"][i]["content"]["membership"] ?? "", - directChatRoomId: "", - avatar_url: - MxContent(res["chunk"][i]["content"]["avatar_url"] ?? "")); - if (newUser.status != "leave") participants.add(newUser); + membership: res["chunk"][i]["content"]["membership"] ?? "", + avatarUrl: + MxContent(res["chunk"][i]["content"]["avatar_url"] ?? ""), + room: this); + if (newUser.membership != "leave") participants.add(newUser); } this.participants = participants; diff --git a/lib/src/Store.dart b/lib/src/Store.dart index 34b66d0..ab60c3a 100644 --- a/lib/src/Store.dart +++ b/lib/src/Store.dart @@ -62,6 +62,7 @@ class Store { if (oldVersion != newVersion) { await db.execute("DROP TABLE IF EXISTS Rooms"); await db.execute("DROP TABLE IF EXISTS Participants"); + await db.execute("DROP TABLE IF EXISTS User"); await db.execute("DROP TABLE IF EXISTS Events"); db.rawUpdate("UPDATE Clients SET prev_batch='' WHERE client=?", [client.clientName]); @@ -92,7 +93,7 @@ class Store { Future createTables(Database db) async{ await db.execute(ClientsScheme); await db.execute(RoomsScheme); - await db.execute(ParticipantsScheme); + await db.execute(UserScheme); await db.execute(EventsScheme); } @@ -122,7 +123,7 @@ class Store { Future clear() async{ await _db.rawDelete("DELETE FROM Clients WHERE client=?", [client.clientName]); await _db.rawDelete("DELETE FROM Rooms"); - await _db.rawDelete("DELETE FROM Participants"); + await _db.rawDelete("DELETE FROM User"); await _db.rawDelete("DELETE FROM Events"); return; } @@ -284,14 +285,14 @@ class Store { } // Update membership table - txn.rawInsert("INSERT OR IGNORE INTO Participants VALUES(?,?,?,?,?,0)", [ + txn.rawInsert("INSERT OR IGNORE INTO User VALUES(?,?,?,?,?,0)", [ chat_id, state_key, insertDisplayname, insertAvatarUrl, membership ]); - String queryStr = "UPDATE Participants SET membership=?"; + String queryStr = "UPDATE User SET membership=?"; List queryArgs = [membership]; if (eventContent["content"]["displayname"] is String) { @@ -366,10 +367,10 @@ class Store { .forEach((String user, dynamic value) async { num power_level = eventContent["content"]["users"][user]; txn.rawUpdate( - "UPDATE Participants SET power_level=? WHERE matrix_id=? AND chat_id=?", + "UPDATE User SET power_level=? WHERE matrix_id=? AND chat_id=?", [power_level, user, chat_id]); txn.rawInsert( - "INSERT OR IGNORE INTO Participants VALUES(?, ?, '', '', ?, ?)", + "INSERT OR IGNORE INTO User VALUES(?, ?, '', '', ?, ?)", [chat_id, user, "unknown", power_level]); }); } @@ -377,59 +378,59 @@ class Store { } } - /// Returns a User object by a given Matrix ID and a Room ID. + /// Returns a User object by a given Matrix ID and a Room. Future getUser( - {String matrixID, String roomID}) async { + {String matrixID, Room room}) async { List> res = await db.rawQuery( - "SELECT * FROM Participants WHERE matrix_id=? AND chat_id=?", - [matrixID, roomID]); + "SELECT * FROM User WHERE matrix_id=? AND chat_id=?", + [matrixID, room.id]); if (res.length != 1) return null; - return User.fromJson(res[0]); + return User.fromJson(res[0], room); } /// Loads all Users in the database to provide a contact list. Future> loadContacts() async { List> res = await db.rawQuery( - "SELECT * FROM Participants WHERE matrix_id!=? GROUP BY matrix_id ORDER BY displayname", + "SELECT * FROM User WHERE matrix_id!=? GROUP BY matrix_id ORDER BY displayname", [client.userID]); List userList = []; - for (int i = 0; i < res.length; i++) userList.add(User.fromJson(res[i])); + for (int i = 0; i < res.length; i++) userList.add(User.fromJson(res[i], null)); return userList; } /// Returns all users of a room by a given [roomID]. - Future> loadParticipants(String roomID) async { + Future> loadParticipants(Room room) async { List> res = await db.rawQuery( "SELECT * " + - " FROM Participants " + + " FROM User " + " WHERE chat_id=? " + " AND membership='join'", - [roomID]); + [room.id]); List participants = []; for (num i = 0; i < res.length; i++) { - participants.add(User.fromJson(res[i])); + participants.add(User.fromJson(res[i], room)); } return participants; } /// Returns a list of events for the given room and sets all participants. - Future> getEventList(String roomID) async{ + Future> getEventList(Room room) async{ List> eventRes = await db.rawQuery( "SELECT * " + - " FROM Events events, Participants participants " + + " FROM Events events, User user " + " WHERE events.chat_id=?" + - " AND events.sender=participants.matrix_id " + + " AND events.sender=user.matrix_id " + " GROUP BY events.id " + " ORDER BY origin_server_ts DESC", - [roomID]); + [room.id]); List eventList = []; for (num i = 0; i < eventRes.length; i++) - eventList.add(Event.fromJson(eventRes[i])); + eventList.add(Event.fromJson(eventRes[i], room)); return eventList; } @@ -469,10 +470,10 @@ class Store { String roomID) async { String avatarStr = ""; List> res = await db.rawQuery( - "SELECT avatar_url FROM Participants " + - " WHERE Participants.chat_id=? " + - " AND (Participants.membership='join' OR Participants.membership='invite') " + - " AND Participants.matrix_id!=? ", + "SELECT avatar_url FROM User " + + " WHERE User.chat_id=? " + + " AND (User.membership='join' OR User.membership='invite') " + + " AND User.matrix_id!=? ", [roomID, client.userID]); if (res.length == 1) avatarStr = res[0]["avatar_url"]; return avatarStr; @@ -485,10 +486,10 @@ class Store { String roomID) async { String displayname = 'Empty chat'; List> rs = await db.rawQuery( - "SELECT Participants.displayname, Participants.matrix_id, Participants.membership FROM Participants " + - " WHERE Participants.chat_id=? " + - " AND (Participants.membership='join' OR Participants.membership='invite') " + - " AND Participants.matrix_id!=? ", + "SELECT User.displayname, User.matrix_id, User.membership FROM User " + + " WHERE User.chat_id=? " + + " AND (User.membership='join' OR User.membership='invite') " + + " AND User.matrix_id!=? ", [roomID, client.userID]); if (rs.length > 0) { displayname = ""; @@ -572,7 +573,7 @@ class Store { 'UNIQUE(id))'; /// The database sheme for the User class. - static final String ParticipantsScheme = 'CREATE TABLE IF NOT EXISTS Participants(' + + static final String UserScheme = 'CREATE TABLE IF NOT EXISTS User(' + 'chat_id TEXT, ' + // The chat id of this membership 'matrix_id TEXT, ' + // The matrix id of this user 'displayname TEXT, ' + diff --git a/lib/src/User.dart b/lib/src/User.dart index 410100d..e38c6bc 100644 --- a/lib/src/User.dart +++ b/lib/src/User.dart @@ -28,43 +28,79 @@ import 'package:famedlysdk/src/Room.dart'; /// Represents a Matrix User which may be a participant in a Matrix Room. class User { - /// The membership status of the user - final String status; - - /// The full qualified Matrix ID in the format @username:server.abc - final String mxid; + /// The full qualified Matrix ID in the format @username:server.abc. + final String id; /// The displayname of the user if the user has set one. final String displayName; + /// The membership status of the user. One of: + /// join + /// invite + /// leave + /// ban + String membership; + /// The avatar if the user has one. - final MxContent avatar_url; + MxContent avatarUrl; - final String directChatRoomId; + /// The powerLevel of the user. Normally: + /// 0=Normal user + /// 50=Moderator + /// 100=Admin + int powerLevel = 0; + /// All users normally belong to a room. final Room room; - const User( - this.mxid, { - this.status, + @Deprecated("Use membership instead!") + String get status => membership; + + @Deprecated("Use ID instead!") + String get mxid => id; + + @Deprecated("Use avatarUrl instead!") + MxContent get avatar_url => avatarUrl; + + User(this.id, { + this.membership, this.displayName, - this.avatar_url, - this.directChatRoomId, + this.avatarUrl, + this.powerLevel, this.room, }); /// Returns the displayname or the local part of the Matrix ID if the user /// has no displayname. - String calcDisplayname() => displayName.isEmpty - ? mxid.replaceFirst("@", "").split(":")[0] - : displayName; + String calcDisplayname() => + displayName.isEmpty + ? mxid.replaceFirst("@", "").split(":")[0] + : displayName; /// Creates a new User object from a json string like a row from the database. - static User fromJson(Map json) { + static User fromJson(Map json, Room room) { return User(json['matrix_id'], displayName: json['displayname'], - avatar_url: MxContent(json['avatar_url']), - status: "", - directChatRoomId: ""); + avatarUrl: MxContent(json['avatar_url']), + membership: "", + room: room); + } + + /// Call the Matrix API to kick this user from this room. + Future kick() async { + dynamic res = await room.kick(id); + return res; + } + + /// Call the Matrix API to ban this user from this room. + Future ban() async { + dynamic res = await room.ban(id); + return res; + } + + /// Call the Matrix API to unban this banned user from this room. + Future unban() async { + dynamic res = await room.unban(id); + return res; } }