@@ -7,8 +7,8 @@ module soulfind.server.cmdhandler;
77@safe :
88
99import soulfind.db : Sdb;
10- import soulfind.defines : blue, kick_duration, log_user, norm, RoomType ,
11- server_username;
10+ import soulfind.defines : blue, kick_duration, log_user, norm, RoomMemberType ,
11+ RoomType, server_username;
1212import soulfind.server.messages;
1313import soulfind.server.room : Room;
1414import soulfind.server.server : Server;
@@ -49,8 +49,18 @@ final class CommandHandler
4949 case " help" :
5050 respond(
5151 sender_username,
52- " Available commands:"
53- ~ " \n\n deleteaccount\n Delete your account"
52+ text(
53+ " Available commands:" ,
54+ " \n\n exportdata\n Export your account data" ,
55+ " \n\n deleteaccount\n Delete your account"
56+ )
57+ );
58+ break ;
59+
60+ case " exportdata" :
61+ respond(
62+ sender_username,
63+ " Account data in JSON format:\n " ~ user_export(sender_username)
5464 );
5565 break ;
5666
@@ -96,6 +106,7 @@ final class CommandHandler
96106 " \n\n admins\n List admins" ,
97107 " \n\n users [connected|banned|privileged]\n List users" ,
98108 " \n\n rooms\n List public rooms" ,
109+ " \n\n exportdata\n Export your account data" ,
99110 " \n\n userinfo <user>\n Show info about user" ,
100111 " \n\n roominfo <room>\n Show info about public room" ,
101112 " \n\n removetickers <user>\n Remove user's public room" ,
@@ -159,6 +170,13 @@ final class CommandHandler
159170 respond(admin_username, output[]);
160171 break ;
161172
173+ case " exportdata" :
174+ respond(
175+ admin_username,
176+ " Account data in JSON format:\n " ~ user_export(admin_username)
177+ );
178+ break ;
179+
162180 case " userinfo" :
163181 if (args.length < 2 ) {
164182 respond(admin_username, " Syntax is: userinfo <user>" );
@@ -517,10 +535,10 @@ final class CommandHandler
517535 auto joined_global_room = " no" ;
518536 auto admin = " no" ;
519537 auto banned = " no" ;
520- auto searchable = " yes" ;
521538 auto privileged = " no" ;
522539 SysTime privileged_until;
523540 auto supporter = " no" ;
541+ auto searchable = " yes" ;
524542 uint upload_speed;
525543 uint shared_files, shared_folders;
526544 const tickers = server.db.user_tickers! (RoomType._public)(username);
@@ -573,12 +591,12 @@ final class CommandHandler
573591 else if (banned_until > now)
574592 banned = text(" until " , banned_until.toSimpleString);
575593
576- if (server.db.is_user_unsearchable(username))
577- searchable = " no" ;
578-
579594 if (privileged_until > now)
580595 privileged = text(" until " , privileged_until.toSimpleString);
581596
597+ if (server.db.is_user_unsearchable(username))
598+ searchable = " no" ;
599+
582600 Appender! string output;
583601 output ~= text(
584602 username,
@@ -600,23 +618,143 @@ final class CommandHandler
600618 " \n Presistent info:" ,
601619 " \n admin: " , admin,
602620 " \n banned: " , banned,
603- " \n searchable: " , searchable,
604621 " \n privileged: " , privileged,
605622 " \n supporter: " , supporter,
623+ " \n searchable: " , searchable,
606624 " \n upload speed: " , upload_speed,
607625 " \n files: " , shared_files,
608- " \n dirs : " , shared_folders,
626+ " \n folders : " , shared_folders,
609627 " \n public tickers: " , tickers.length
610628 );
611629
612630 if (tickers.length > 0 ) {
613- output ~= text(" \n\n Public room tickers (" , tickers.length, " ):" );
614631 foreach (ticker ; tickers) {
615632 const room_name = ticker[0 ], content = ticker[1 ];
616- output ~= text(" \n [" , room_name, " ] " , content);
633+ output ~= text(" \n [" , room_name, " ] " , content);
634+ }
635+ }
636+
637+ return output[];
638+ }
639+
640+ private string user_export (string username)
641+ {
642+ auto user = server.get_user(username);
643+ const status = (user.status == UserStatus.away) ? " away" : " online" ;
644+ auto obfuscation_type = " null" ;
645+ const joined_rooms = user.joined_room_names! (RoomType.any);
646+ const accept_invitations = (
647+ user.accept_room_invitations ? " true" : " false"
648+ );
649+ const joined_global_room = (
650+ server.is_global_room_joined(username) ? " true" : " false"
651+ );
652+ const admin_until = server.db.admin_until(username);
653+ auto admin = (admin_until > SysTime())
654+ ? text(" \" " , admin_until.toISOExtString, " \" " )
655+ : " null" ;
656+ const privileged_until = user.privileged_until;
657+ auto privileged = (privileged_until > SysTime())
658+ ? text(" \" " , privileged_until.toISOExtString, " \" " )
659+ : " null" ;
660+ const supporter = user.supporter ? " true" : " false" ;
661+ const searchable = (
662+ server.is_user_unsearchable(username) ? " false" : " true"
663+ );
664+ const private_rooms_owner = server.db.rooms(username);
665+ const private_rooms_member = server.db.rooms(null , username);
666+ const private_rooms_op = server.db.rooms(
667+ null , username, RoomMemberType.operator
668+ );
669+
670+ if (user.obfuscation_type == ObfuscationType.rotated)
671+ obfuscation_type = " \" rotated\" " ;
672+ else if (user.obfuscation_type != ObfuscationType.none)
673+ obfuscation_type = text(
674+ " \" " , (cast (uint ) user.obfuscation_type).text, " \" "
675+ );
676+
677+ Appender! string output;
678+ output ~= text(
679+ " {" ,
680+ " \n \" username\" : \" " , username, " \" ," ,
681+ " \n \" session_data\" : {" ,
682+ " \n \" status\" : \" " , status, " \" ," ,
683+ " \n \" client_version\" : \" " , user.client_version, " \" ," ,
684+ " \n \" ip_address\" : \" " , user.address.toAddrString ~ " \" ," ,
685+ " \n \" port\" : " , user.address.port, " ," ,
686+ " \n \" obfuscated_port\" : " , user.obfuscated_port, " ," ,
687+ " \n \" obfuscation_type\" : " , obfuscation_type, " ," ,
688+ " \n \" accept_room_invitations\" : " , accept_invitations, " ," ,
689+ " \n \" joined_global_room\" : " , joined_global_room, " ," ,
690+ " \n \" liked_items\" : " , user.liked_item_names, " ," ,
691+ " \n \" hated_items\" : " , user.hated_item_names, " ," ,
692+ " \n \" joined_rooms\" : " , joined_rooms, " ," ,
693+ " \n \" watched_users\" : " , user.watched_usernames,
694+ " \n }," ,
695+ " \n \" persistent_data\" : {" ,
696+ " \n \" admin_until\" : " , admin, " ," ,
697+ " \n \" privileged_until\" : " , privileged, " ," ,
698+ " \n \" supporter\" : " , supporter, " ," ,
699+ " \n \" searchable\" : " , searchable, " ," ,
700+ " \n \" num_files\" : " , user.shared_files, " ," ,
701+ " \n \" num_folders\" : " , user.shared_folders, " ," ,
702+ " \n \" upload_speed\" : " , user.upload_speed, " ," ,
703+ " \n \" private_rooms_owner\" : " , private_rooms_owner, " ," ,
704+ " \n \" private_rooms_member\" : " , private_rooms_member, " ," ,
705+ " \n \" private_rooms_operator\" : " , private_rooms_op, " ," ,
706+ " \n \" room_tickers\" : {" ,
707+ );
708+
709+ const tickers = server.db.user_tickers! (RoomType.any)(username);
710+ if (tickers.length > 0 ) {
711+ auto first = true ;
712+ foreach (ticker ; tickers) {
713+ const room_name = ticker[0 ], content = ticker[1 ];
714+ if (! first) output ~= " ," ;
715+ output ~= text(
716+ " \n \" " , room_name, " \" : \" " , content, " \" "
717+ );
718+ first = false ;
719+ }
720+ output ~= " \n " ;
721+ }
722+
723+ output ~= text(
724+ " }," ,
725+ " \n }," ,
726+ " \n \" volatile_data\" : {" ,
727+ " \n \" private_messages_queued\" : [" ,
728+ );
729+
730+ const pms = server.get_queued_pms(username);
731+ if (pms.length > 0 ) {
732+ auto first = true ;
733+ foreach (pm ; pms) {
734+ const id = pm.id;
735+ const to_username = pm.to_username;
736+ const timestamp = pm.time.toISOExtString(0 );
737+ const message = pm.message;
738+
739+ if (! first) output ~= " ," ;
740+ output ~= text(
741+ " \n {" ,
742+ " \n \" id\" : \" " , id, " \" " ,
743+ " \n \" recipient\" : \" " , to_username, " \" " ,
744+ " \n \" timestamp\" : \" " , timestamp, " \" ," ,
745+ " \n \" message\" : \" " , message, " \" " ,
746+ " \n }"
747+ );
748+ first = false ;
617749 }
750+ output ~= " \n " ;
618751 }
619752
753+ output ~= text(
754+ " ]" ,
755+ " \n }" ,
756+ " \n }"
757+ );
620758 return output[];
621759 }
622760}
0 commit comments