Refactor User class

This commit is contained in:
Christian Pauly 2019-06-11 11:13:14 +02:00
parent efa2ed5379
commit 6b94ac220f
4 changed files with 100 additions and 62 deletions

View file

@ -25,6 +25,7 @@ import 'dart:convert';
import 'package:famedlysdk/src/utils/ChatTime.dart'; import 'package:famedlysdk/src/utils/ChatTime.dart';
import 'package:famedlysdk/src/Client.dart'; import 'package:famedlysdk/src/Client.dart';
import './User.dart'; import './User.dart';
import './Room.dart';
/// A single Matrix event, e.g. a message in a chat. /// A single Matrix event, e.g. a message in a chat.
class Event { class Event {
@ -77,7 +78,7 @@ class Event {
} }
static Event fromJson(Map<String, dynamic> jsonObj) { static Event fromJson(Map<String, dynamic> jsonObj, Room room) {
Map<String,dynamic> content; Map<String,dynamic> content;
try { try {
content = json.decode(jsonObj["content_json"]); content = json.decode(jsonObj["content_json"]);
@ -87,7 +88,7 @@ class Event {
} }
return Event( return Event(
jsonObj["id"], jsonObj["id"],
User.fromJson(jsonObj), User.fromJson(jsonObj, room),
ChatTime(jsonObj["origin_server_ts"]), ChatTime(jsonObj["origin_server_ts"]),
stateKey: User(jsonObj["state_key"]), stateKey: User(jsonObj["state_key"]),
environment: jsonObj["type"], environment: jsonObj["type"],
@ -97,7 +98,7 @@ class Event {
); );
} }
static Future<List<Event>> getEventList(Client matrix, String roomID) async{ static Future<List<Event>> getEventList(Client matrix, Room room) async{
List<Map<String, dynamic>> eventRes = await matrix.store.db.rawQuery( List<Map<String, dynamic>> eventRes = await matrix.store.db.rawQuery(
"SELECT * " + "SELECT * " +
" FROM Events events, Participants participants " + " FROM Events events, Participants participants " +
@ -105,12 +106,12 @@ class Event {
" AND events.sender=participants.matrix_id " + " AND events.sender=participants.matrix_id " +
" GROUP BY events.id " + " GROUP BY events.id " +
" ORDER BY origin_server_ts DESC", " ORDER BY origin_server_ts DESC",
[roomID]); [room.id]);
List<Event> eventList = []; List<Event> eventList = [];
for (num i = 0; i < eventRes.length; i++) for (num i = 0; i < eventRes.length; i++)
eventList.add(Event.fromJson(eventRes[i])); eventList.add(Event.fromJson(eventRes[i], room));
return eventList; return eventList;
} }

View file

@ -287,7 +287,7 @@ class Room {
/// Load all events for a given room from the store. This includes all /// 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. /// senders of those events, who will be added to the participants list.
Future<List<Event>> loadEvents() async { Future<List<Event>> loadEvents() async {
this.events = await client.store.getEventList(id); this.events = await client.store.getEventList(this);
Map<String,bool> participantMap = {}; Map<String,bool> participantMap = {};
for (num i = 0; i < events.length; i++) { for (num i = 0; i < events.length; i++) {
@ -302,7 +302,7 @@ class Room {
/// Load all participants for a given room from the store. /// Load all participants for a given room from the store.
Future<List<User>> loadParticipants() async { Future<List<User>> loadParticipants() async {
this.participants = await client.store.loadParticipants(id); this.participants = await client.store.loadParticipants(this);
return this.participants; return this.participants;
} }
@ -319,11 +319,11 @@ class Room {
for (num i = 0; i < res["chunk"].length; i++) { for (num i = 0; i < res["chunk"].length; i++) {
User newUser = User(res["chunk"][i]["state_key"], User newUser = User(res["chunk"][i]["state_key"],
displayName: res["chunk"][i]["content"]["displayname"] ?? "", displayName: res["chunk"][i]["content"]["displayname"] ?? "",
status: res["chunk"][i]["content"]["membership"] ?? "", membership: res["chunk"][i]["content"]["membership"] ?? "",
directChatRoomId: "", avatarUrl:
avatar_url: MxContent(res["chunk"][i]["content"]["avatar_url"] ?? ""),
MxContent(res["chunk"][i]["content"]["avatar_url"] ?? "")); room: this);
if (newUser.status != "leave") participants.add(newUser); if (newUser.membership != "leave") participants.add(newUser);
} }
this.participants = participants; this.participants = participants;

View file

@ -62,6 +62,7 @@ class Store {
if (oldVersion != newVersion) { if (oldVersion != newVersion) {
await db.execute("DROP TABLE IF EXISTS Rooms"); await db.execute("DROP TABLE IF EXISTS Rooms");
await db.execute("DROP TABLE IF EXISTS Participants"); await db.execute("DROP TABLE IF EXISTS Participants");
await db.execute("DROP TABLE IF EXISTS User");
await db.execute("DROP TABLE IF EXISTS Events"); await db.execute("DROP TABLE IF EXISTS Events");
db.rawUpdate("UPDATE Clients SET prev_batch='' WHERE client=?", db.rawUpdate("UPDATE Clients SET prev_batch='' WHERE client=?",
[client.clientName]); [client.clientName]);
@ -92,7 +93,7 @@ class Store {
Future<void> createTables(Database db) async{ Future<void> createTables(Database db) async{
await db.execute(ClientsScheme); await db.execute(ClientsScheme);
await db.execute(RoomsScheme); await db.execute(RoomsScheme);
await db.execute(ParticipantsScheme); await db.execute(UserScheme);
await db.execute(EventsScheme); await db.execute(EventsScheme);
} }
@ -122,7 +123,7 @@ class Store {
Future<void> clear() async{ Future<void> clear() async{
await _db.rawDelete("DELETE FROM Clients WHERE client=?", [client.clientName]); await _db.rawDelete("DELETE FROM Clients WHERE client=?", [client.clientName]);
await _db.rawDelete("DELETE FROM Rooms"); await _db.rawDelete("DELETE FROM Rooms");
await _db.rawDelete("DELETE FROM Participants"); await _db.rawDelete("DELETE FROM User");
await _db.rawDelete("DELETE FROM Events"); await _db.rawDelete("DELETE FROM Events");
return; return;
} }
@ -284,14 +285,14 @@ class Store {
} }
// Update membership table // Update membership table
txn.rawInsert("INSERT OR IGNORE INTO Participants VALUES(?,?,?,?,?,0)", [ txn.rawInsert("INSERT OR IGNORE INTO User VALUES(?,?,?,?,?,0)", [
chat_id, chat_id,
state_key, state_key,
insertDisplayname, insertDisplayname,
insertAvatarUrl, insertAvatarUrl,
membership membership
]); ]);
String queryStr = "UPDATE Participants SET membership=?"; String queryStr = "UPDATE User SET membership=?";
List<String> queryArgs = [membership]; List<String> queryArgs = [membership];
if (eventContent["content"]["displayname"] is String) { if (eventContent["content"]["displayname"] is String) {
@ -366,10 +367,10 @@ class Store {
.forEach((String user, dynamic value) async { .forEach((String user, dynamic value) async {
num power_level = eventContent["content"]["users"][user]; num power_level = eventContent["content"]["users"][user];
txn.rawUpdate( 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]); [power_level, user, chat_id]);
txn.rawInsert( txn.rawInsert(
"INSERT OR IGNORE INTO Participants VALUES(?, ?, '', '', ?, ?)", "INSERT OR IGNORE INTO User VALUES(?, ?, '', '', ?, ?)",
[chat_id, user, "unknown", power_level]); [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<User> getUser( Future<User> getUser(
{String matrixID, String roomID}) async { {String matrixID, Room room}) async {
List<Map<String, dynamic>> res = await db.rawQuery( List<Map<String, dynamic>> res = await db.rawQuery(
"SELECT * FROM Participants WHERE matrix_id=? AND chat_id=?", "SELECT * FROM User WHERE matrix_id=? AND chat_id=?",
[matrixID, roomID]); [matrixID, room.id]);
if (res.length != 1) return null; 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. /// Loads all Users in the database to provide a contact list.
Future<List<User>> loadContacts() async { Future<List<User>> loadContacts() async {
List<Map<String, dynamic>> res = await db.rawQuery( List<Map<String, dynamic>> 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]); [client.userID]);
List<User> userList = []; List<User> 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; return userList;
} }
/// Returns all users of a room by a given [roomID]. /// Returns all users of a room by a given [roomID].
Future<List<User>> loadParticipants(String roomID) async { Future<List<User>> loadParticipants(Room room) async {
List<Map<String, dynamic>> res = await db.rawQuery( List<Map<String, dynamic>> res = await db.rawQuery(
"SELECT * " + "SELECT * " +
" FROM Participants " + " FROM User " +
" WHERE chat_id=? " + " WHERE chat_id=? " +
" AND membership='join'", " AND membership='join'",
[roomID]); [room.id]);
List<User> participants = []; List<User> participants = [];
for (num i = 0; i < res.length; i++) { for (num i = 0; i < res.length; i++) {
participants.add(User.fromJson(res[i])); participants.add(User.fromJson(res[i], room));
} }
return participants; return participants;
} }
/// Returns a list of events for the given room and sets all participants. /// Returns a list of events for the given room and sets all participants.
Future<List<Event>> getEventList(String roomID) async{ Future<List<Event>> getEventList(Room room) async{
List<Map<String, dynamic>> eventRes = await db.rawQuery( List<Map<String, dynamic>> eventRes = await db.rawQuery(
"SELECT * " + "SELECT * " +
" FROM Events events, Participants participants " + " FROM Events events, User user " +
" WHERE events.chat_id=?" + " WHERE events.chat_id=?" +
" AND events.sender=participants.matrix_id " + " AND events.sender=user.matrix_id " +
" GROUP BY events.id " + " GROUP BY events.id " +
" ORDER BY origin_server_ts DESC", " ORDER BY origin_server_ts DESC",
[roomID]); [room.id]);
List<Event> eventList = []; List<Event> eventList = [];
for (num i = 0; i < eventRes.length; i++) for (num i = 0; i < eventRes.length; i++)
eventList.add(Event.fromJson(eventRes[i])); eventList.add(Event.fromJson(eventRes[i], room));
return eventList; return eventList;
} }
@ -469,10 +470,10 @@ class Store {
String roomID) async { String roomID) async {
String avatarStr = ""; String avatarStr = "";
List<Map<String, dynamic>> res = await db.rawQuery( List<Map<String, dynamic>> res = await db.rawQuery(
"SELECT avatar_url FROM Participants " + "SELECT avatar_url FROM User " +
" WHERE Participants.chat_id=? " + " WHERE User.chat_id=? " +
" AND (Participants.membership='join' OR Participants.membership='invite') " + " AND (User.membership='join' OR User.membership='invite') " +
" AND Participants.matrix_id!=? ", " AND User.matrix_id!=? ",
[roomID, client.userID]); [roomID, client.userID]);
if (res.length == 1) avatarStr = res[0]["avatar_url"]; if (res.length == 1) avatarStr = res[0]["avatar_url"];
return avatarStr; return avatarStr;
@ -485,10 +486,10 @@ class Store {
String roomID) async { String roomID) async {
String displayname = 'Empty chat'; String displayname = 'Empty chat';
List<Map<String, dynamic>> rs = await db.rawQuery( List<Map<String, dynamic>> rs = await db.rawQuery(
"SELECT Participants.displayname, Participants.matrix_id, Participants.membership FROM Participants " + "SELECT User.displayname, User.matrix_id, User.membership FROM User " +
" WHERE Participants.chat_id=? " + " WHERE User.chat_id=? " +
" AND (Participants.membership='join' OR Participants.membership='invite') " + " AND (User.membership='join' OR User.membership='invite') " +
" AND Participants.matrix_id!=? ", " AND User.matrix_id!=? ",
[roomID, client.userID]); [roomID, client.userID]);
if (rs.length > 0) { if (rs.length > 0) {
displayname = ""; displayname = "";
@ -572,7 +573,7 @@ class Store {
'UNIQUE(id))'; 'UNIQUE(id))';
/// The database sheme for the User class. /// 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 'chat_id TEXT, ' + // The chat id of this membership
'matrix_id TEXT, ' + // The matrix id of this user 'matrix_id TEXT, ' + // The matrix id of this user
'displayname TEXT, ' + 'displayname TEXT, ' +

View file

@ -28,43 +28,79 @@ import 'package:famedlysdk/src/Room.dart';
/// Represents a Matrix User which may be a participant in a Matrix Room. /// Represents a Matrix User which may be a participant in a Matrix Room.
class User { class User {
/// The membership status of the user /// The full qualified Matrix ID in the format @username:server.abc.
final String status; final String id;
/// The full qualified Matrix ID in the format @username:server.abc
final String mxid;
/// The displayname of the user if the user has set one. /// The displayname of the user if the user has set one.
final String displayName; final String displayName;
/// The membership status of the user. One of:
/// join
/// invite
/// leave
/// ban
String membership;
/// The avatar if the user has one. /// 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; final Room room;
const User( @Deprecated("Use membership instead!")
this.mxid, { String get status => membership;
this.status,
@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.displayName,
this.avatar_url, this.avatarUrl,
this.directChatRoomId, this.powerLevel,
this.room, this.room,
}); });
/// Returns the displayname or the local part of the Matrix ID if the user /// Returns the displayname or the local part of the Matrix ID if the user
/// has no displayname. /// has no displayname.
String calcDisplayname() => displayName.isEmpty String calcDisplayname() =>
displayName.isEmpty
? mxid.replaceFirst("@", "").split(":")[0] ? mxid.replaceFirst("@", "").split(":")[0]
: displayName; : displayName;
/// Creates a new User object from a json string like a row from the database. /// Creates a new User object from a json string like a row from the database.
static User fromJson(Map<String, dynamic> json) { static User fromJson(Map<String, dynamic> json, Room room) {
return User(json['matrix_id'], return User(json['matrix_id'],
displayName: json['displayname'], displayName: json['displayname'],
avatar_url: MxContent(json['avatar_url']), avatarUrl: MxContent(json['avatar_url']),
status: "", membership: "",
directChatRoomId: ""); room: room);
}
/// Call the Matrix API to kick this user from this room.
Future<dynamic> kick() async {
dynamic res = await room.kick(id);
return res;
}
/// Call the Matrix API to ban this user from this room.
Future<dynamic> ban() async {
dynamic res = await room.ban(id);
return res;
}
/// Call the Matrix API to unban this banned user from this room.
Future<dynamic> unban() async {
dynamic res = await room.unban(id);
return res;
} }
} }