Skip to content

Commit 48e8ab4

Browse files
committed
db.d: make room member/operatorship operations atomic
1 parent a42469d commit 48e8ab4

File tree

4 files changed

+124
-95
lines changed

4 files changed

+124
-95
lines changed

src/db.d

Lines changed: 85 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -965,27 +965,6 @@ final class Database
965965
return RoomType.non_existent;
966966
}
967967

968-
string get_room_owner(string room_name)
969-
{
970-
enum sql = text(
971-
"SELECT owner FROM ", rooms_table, " WHERE room = ? AND type = ?;"
972-
);
973-
const res = query(sql, [room_name, text(cast(int) RoomType._private)]);
974-
return res.length > 0 ? res[0][0] : null;
975-
}
976-
977-
bool is_room_member(string room_name, string username)
978-
{
979-
enum sql = text(
980-
"SELECT 1 FROM ", rooms_table, " WHERE room = ? AND owner = ?",
981-
" UNION ALL ",
982-
"SELECT 1 FROM ", room_members_table,
983-
" WHERE room = ? AND username = ?;"
984-
);
985-
const res = query(sql, [room_name, username, room_name, username]);
986-
return res.length > 0;
987-
}
988-
989968
string[] rooms(string owner = null,
990969
string member = null,
991970
RoomMemberType member_type = RoomMemberType.any)
@@ -1020,26 +999,102 @@ final class Database
1020999
return rooms[];
10211000
}
10221001

1023-
void add_room_member(RoomMemberType type)(string room_name,
1024-
string username)
1002+
bool add_room_member(string room_name, string username)
10251003
{
1026-
if (type < 0)
1027-
return;
1028-
10291004
enum sql = text(
1030-
"REPLACE INTO ", room_members_table,
1005+
"INSERT OR IGNORE INTO ", room_members_table,
10311006
"(room, username, type) VALUES(?, ?, ?);"
10321007
);
1033-
query(sql, [room_name, username, text(cast(int) type)]);
1008+
enum type = text(cast(int) RoomMemberType.normal);
1009+
query(sql, [room_name, username, type]);
1010+
1011+
if (changes() == 0)
1012+
return false;
1013+
1014+
if (log_db) writeln(
1015+
"[DB] Added member ", blue, username, norm, " to room ",
1016+
blue, room_name, norm
1017+
);
1018+
return true;
10341019
}
10351020

1036-
void del_room_member(string room_name, string username)
1021+
bool del_room_member(string room_name, string username)
10371022
{
10381023
enum sql = text(
10391024
"DELETE FROM ", room_members_table,
1025+
" WHERE room = ? AND username = ? AND type != ?;"
1026+
);
1027+
enum type = text(cast(int) RoomMemberType.operator);
1028+
query(sql, [room_name, username, type]);
1029+
1030+
if (changes() == 0)
1031+
return false;
1032+
1033+
if (log_db) writeln(
1034+
"[DB] Removed member ", blue, username, norm, " from room ",
1035+
blue, room_name, norm
1036+
);
1037+
return true;
1038+
}
1039+
1040+
bool grant_room_operatorship(string room_name, string username)
1041+
{
1042+
enum sql = text(
1043+
"UPDATE ", room_members_table, " SET type = ?",
1044+
" WHERE room = ? AND username = ? AND type != ?;"
1045+
);
1046+
enum type = text(cast(int) RoomMemberType.operator);
1047+
query(sql, [type, room_name, username, type]);
1048+
1049+
if (changes() == 0)
1050+
return false;
1051+
1052+
if (log_db) writeln(
1053+
"[DB] Granted user ", blue, username, norm,
1054+
" operatorship in room ", blue, room_name, norm
1055+
);
1056+
return true;
1057+
}
1058+
1059+
bool revoke_room_operatorship(string room_name, string username)
1060+
{
1061+
enum sql = text(
1062+
"UPDATE ", room_members_table, " SET type = ?",
1063+
" WHERE room = ? AND username = ? AND type = ?;"
1064+
);
1065+
enum new_type = text(cast(int) RoomMemberType.normal);
1066+
enum old_type = text(cast(int) RoomMemberType.operator);
1067+
query(sql, [new_type, room_name, username, old_type]);
1068+
1069+
if (changes() == 0)
1070+
return false;
1071+
1072+
if (log_db) writeln(
1073+
"[DB] Revoked user ", blue, username, norm,
1074+
"'s operatorship in room ", blue, room_name, norm
1075+
);
1076+
return true;
1077+
}
1078+
1079+
bool can_access_room(string room_name, string username)
1080+
{
1081+
enum sql = text(
1082+
"SELECT 1 FROM ", rooms_table, " WHERE room = ? AND owner = ?",
1083+
" UNION ALL ",
1084+
"SELECT 1 FROM ", room_members_table,
10401085
" WHERE room = ? AND username = ?;"
10411086
);
1042-
query(sql, [room_name, username]);
1087+
const res = query(sql, [room_name, username, room_name, username]);
1088+
return res.length > 0;
1089+
}
1090+
1091+
string get_room_owner(string room_name)
1092+
{
1093+
enum sql = text(
1094+
"SELECT owner FROM ", rooms_table, " WHERE room = ? AND type = ?;"
1095+
);
1096+
const res = query(sql, [room_name, text(cast(int) RoomType._private)]);
1097+
return res.length > 0 ? res[0][0] : null;
10431098
}
10441099

10451100
RoomMemberType get_room_member_type(string room_name, string username)

src/server/room.d

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,11 @@ final class Room
8282
return (username in users) ? true : false;
8383
}
8484

85-
bool is_member(string username)
85+
bool can_access(string username)
8686
{
87-
return is_joined(username) || db.is_room_member(name, username);
87+
return type != RoomType._private
88+
|| is_joined(username)
89+
|| db.can_access_room(name, username);
8890
}
8991

9092
size_t num_users()

src/server/server.d

Lines changed: 27 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ final class Server
114114
if (room is null)
115115
return;
116116

117-
if (room.type == RoomType._private && !room.is_member(username))
117+
if (!room.can_access(username))
118118
return;
119119

120120
if (db.is_search_query_filtered(query))
@@ -479,11 +479,13 @@ final class Server
479479
if (actor == target)
480480
return;
481481

482+
RoomMemberType actor_type;
482483
const owner = db.get_room_owner(room_name);
483-
const room_member_type = db.get_room_member_type(room_name, actor);
484-
485-
if (actor != owner && room_member_type != RoomMemberType.operator)
486-
return;
484+
if (actor != owner) {
485+
actor_type = db.get_room_member_type(room_name, actor);
486+
if (actor_type != RoomMemberType.operator)
487+
return;
488+
}
487489

488490
auto target_user = get_user(target);
489491
if (target_user is null) {
@@ -506,7 +508,7 @@ final class Server
506508
return;
507509
}
508510

509-
if (owner == target) {
511+
if (target == owner) {
510512
send_pm(
511513
server_username, actor,
512514
text(
@@ -517,8 +519,7 @@ final class Server
517519
return;
518520
}
519521

520-
if (db.get_room_member_type(
521-
room_name, target) != RoomMemberType.non_existent) {
522+
if (!db.add_room_member(room_name, target)) {
522523
send_pm(
523524
server_username, actor,
524525
text(
@@ -529,8 +530,6 @@ final class Server
529530
return;
530531
}
531532

532-
db.add_room_member!(RoomMemberType.normal)(room_name, target);
533-
534533
void send_user_msg(string room_username) {
535534
auto room_user = get_user(room_username);
536535
if (room_user is null)
@@ -552,7 +551,7 @@ final class Server
552551
)
553552
);
554553

555-
if (room_member_type == RoomMemberType.operator)
554+
if (actor_type == RoomMemberType.operator)
556555
send_pm(
557556
server_username, owner,
558557
text(
@@ -565,29 +564,17 @@ final class Server
565564

566565
void cancel_room_membership(string room_name, string actor, string target)
567566
{
568-
const target_type = db.get_room_member_type(room_name, target);
569-
if (target_type == RoomMemberType.non_existent)
570-
return;
567+
cancel_room_operatorship(room_name, actor, target);
571568

572569
const owner = db.get_room_owner(room_name);
573-
if (actor != target) {
574-
if (target == owner)
570+
if (actor != target && actor != owner) {
571+
const actor_type = db.get_room_member_type(room_name, actor);
572+
if (actor_type != RoomMemberType.operator)
575573
return;
576-
577-
if (actor != owner) {
578-
if (target_type == RoomMemberType.operator)
579-
return;
580-
581-
const actor_type = db.get_room_member_type(room_name, actor);
582-
if (actor_type != RoomMemberType.operator)
583-
return;
584-
}
585574
}
586575

587-
if (target_type == RoomMemberType.operator)
588-
cancel_room_operatorship(room_name, actor, target);
589-
590-
db.del_room_member(room_name, target);
576+
if (!db.del_room_member(room_name, target))
577+
return;
591578

592579
void send_user_msg(string room_username) {
593580
auto room_user = get_user(room_username);
@@ -632,31 +619,18 @@ final class Server
632619
return;
633620
}
634621

635-
const target_type = db.get_room_member_type(room_name, target);
636-
if (target_type == RoomMemberType.non_existent) {
637-
send_pm(
638-
server_username, actor,
639-
text(
640-
"user ", target, " must first be a member of room ",
641-
room_name
642-
)
622+
if (!db.grant_room_operatorship(room_name, target)) {
623+
const target_type = db.get_room_member_type(room_name, target);
624+
const message = text(
625+
"user ", target,
626+
target_type == RoomMemberType.operator
627+
? " is already an operator of room "
628+
: " must first be a member of room ", room_name
643629
);
630+
send_pm(server_username, actor, message);
644631
return;
645632
}
646633

647-
if (target_type == RoomMemberType.operator) {
648-
send_pm(
649-
server_username, actor,
650-
text(
651-
"user ", target, " is already an operator of room ",
652-
room_name
653-
)
654-
);
655-
return;
656-
}
657-
658-
db.add_room_member!(RoomMemberType.operator)(room_name, target);
659-
660634
void send_user_msg(string room_username) {
661635
auto room_user = get_user(room_username);
662636
if (room_user is null)
@@ -680,15 +654,12 @@ final class Server
680654
void cancel_room_operatorship(string room_name, string actor,
681655
string target)
682656
{
683-
const target_type = db.get_room_member_type(room_name, target);
684-
if (target_type != RoomMemberType.operator)
685-
return;
686-
687657
const owner = db.get_room_owner(room_name);
688-
if (actor != owner && actor != target)
658+
if (actor != target && actor != owner)
689659
return;
690660

691-
db.add_room_member!(RoomMemberType.normal)(room_name, target);
661+
if (!db.revoke_room_operatorship(room_name, target))
662+
return;
692663

693664
void send_user_msg(string room_username) {
694665
auto room_user = get_user(room_username);

src/server/user.d

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -604,13 +604,7 @@ final class User
604604
const owner = (type == RoomType._private) ? username : null;
605605
auto room = server.add_room(room_name, owner);
606606

607-
if (room.type == RoomType._public && type == RoomType._private) {
608-
server.send_pm(
609-
server_username, username,
610-
text("Room (", room_name, ") is registered as public.")
611-
);
612-
}
613-
else if (room.type == RoomType._private && !room.is_member(username)) {
607+
if (!room.can_access(username)) {
614608
scope response_msg = new SCantCreateRoom(room_name);
615609
send_message(response_msg);
616610
server.send_pm(
@@ -623,6 +617,13 @@ final class User
623617
return;
624618
}
625619

620+
if (room.type == RoomType._public && type == RoomType._private) {
621+
server.send_pm(
622+
server_username, username,
623+
text("Room (", room_name, ") is registered as public.")
624+
);
625+
}
626+
626627
joined_rooms[room_name] = room;
627628
room.add_user(this);
628629
}

0 commit comments

Comments
 (0)