]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/admin-settings.tsx
Legal info dess (#666)
[lemmy-ui.git] / src / shared / components / home / admin-settings.tsx
1 import autosize from "autosize";
2 import { Component, linkEvent } from "inferno";
3 import {
4   BannedPersonsResponse,
5   GetBannedPersons,
6   GetSiteConfig,
7   GetSiteConfigResponse,
8   GetSiteResponse,
9   PersonViewSafe,
10   SaveSiteConfig,
11   SiteResponse,
12   UserOperation,
13 } from "lemmy-js-client";
14 import { Subscription } from "rxjs";
15 import { i18n } from "../../i18next";
16 import { InitialFetchRequest } from "../../interfaces";
17 import { WebSocketService } from "../../services";
18 import {
19   authField,
20   capitalizeFirstLetter,
21   isBrowser,
22   randomStr,
23   setIsoData,
24   showLocal,
25   toast,
26   wsClient,
27   wsJsonToRes,
28   wsSubscribe,
29   wsUserOp,
30 } from "../../utils";
31 import { HtmlTags } from "../common/html-tags";
32 import { Spinner } from "../common/icon";
33 import { PersonListing } from "../person/person-listing";
34 import { SiteForm } from "./site-form";
35
36 interface AdminSettingsState {
37   siteRes: GetSiteResponse;
38   siteConfigRes: GetSiteConfigResponse;
39   siteConfigHjson: string;
40   loading: boolean;
41   banned: PersonViewSafe[];
42   siteConfigLoading: boolean;
43   leaveAdminTeamLoading: boolean;
44 }
45
46 export class AdminSettings extends Component<any, AdminSettingsState> {
47   private siteConfigTextAreaId = `site-config-${randomStr()}`;
48   private isoData = setIsoData(this.context);
49   private subscription: Subscription;
50   private emptyState: AdminSettingsState = {
51     siteRes: this.isoData.site_res,
52     siteConfigHjson: null,
53     siteConfigRes: {
54       config_hjson: null,
55     },
56     banned: [],
57     loading: true,
58     siteConfigLoading: null,
59     leaveAdminTeamLoading: null,
60   };
61
62   constructor(props: any, context: any) {
63     super(props, context);
64
65     this.state = this.emptyState;
66
67     this.parseMessage = this.parseMessage.bind(this);
68     this.subscription = wsSubscribe(this.parseMessage);
69
70     // Only fetch the data if coming from another route
71     if (this.isoData.path == this.context.router.route.match.url) {
72       this.state.siteConfigRes = this.isoData.routeData[0];
73       this.state.siteConfigHjson = this.state.siteConfigRes.config_hjson;
74       this.state.banned = this.isoData.routeData[1].banned;
75       this.state.siteConfigLoading = false;
76       this.state.loading = false;
77     } else {
78       WebSocketService.Instance.send(
79         wsClient.getSiteConfig({
80           auth: authField(),
81         })
82       );
83       WebSocketService.Instance.send(
84         wsClient.getBannedPersons({
85           auth: authField(),
86         })
87       );
88     }
89   }
90
91   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
92     let promises: Promise<any>[] = [];
93
94     let siteConfigForm: GetSiteConfig = { auth: req.auth };
95     promises.push(req.client.getSiteConfig(siteConfigForm));
96
97     let bannedPersonsForm: GetBannedPersons = { auth: req.auth };
98     promises.push(req.client.getBannedPersons(bannedPersonsForm));
99
100     return promises;
101   }
102
103   componentDidMount() {
104     if (isBrowser()) {
105       var textarea: any = document.getElementById(this.siteConfigTextAreaId);
106       autosize(textarea);
107     }
108   }
109
110   componentWillUnmount() {
111     if (isBrowser()) {
112       this.subscription.unsubscribe();
113     }
114   }
115
116   get documentTitle(): string {
117     return `${i18n.t("admin_settings")} - ${
118       this.state.siteRes.site_view.site.name
119     }`;
120   }
121
122   render() {
123     return (
124       <div class="container">
125         {this.state.loading ? (
126           <h5>
127             <Spinner large />
128           </h5>
129         ) : (
130           <div class="row">
131             <div class="col-12 col-md-6">
132               <HtmlTags
133                 title={this.documentTitle}
134                 path={this.context.router.route.match.url}
135               />
136               {this.state.siteRes.site_view.site.id && (
137                 <SiteForm
138                   site={this.state.siteRes.site_view.site}
139                   showLocal={showLocal(this.isoData)}
140                 />
141               )}
142               {this.admins()}
143               {this.bannedUsers()}
144             </div>
145             <div class="col-12 col-md-6">{this.adminSettings()}</div>
146           </div>
147         )}
148       </div>
149     );
150   }
151
152   admins() {
153     return (
154       <>
155         <h5>{capitalizeFirstLetter(i18n.t("admins"))}</h5>
156         <ul class="list-unstyled">
157           {this.state.siteRes.admins.map(admin => (
158             <li class="list-inline-item">
159               <PersonListing person={admin.person} />
160             </li>
161           ))}
162         </ul>
163         {this.leaveAdmin()}
164       </>
165     );
166   }
167
168   leaveAdmin() {
169     return (
170       <button
171         onClick={linkEvent(this, this.handleLeaveAdminTeam)}
172         class="btn btn-danger mb-2"
173       >
174         {this.state.leaveAdminTeamLoading ? (
175           <Spinner />
176         ) : (
177           i18n.t("leave_admin_team")
178         )}
179       </button>
180     );
181   }
182
183   bannedUsers() {
184     return (
185       <>
186         <h5>{i18n.t("banned_users")}</h5>
187         <ul class="list-unstyled">
188           {this.state.banned.map(banned => (
189             <li class="list-inline-item">
190               <PersonListing person={banned.person} />
191             </li>
192           ))}
193         </ul>
194       </>
195     );
196   }
197
198   adminSettings() {
199     return (
200       <div>
201         <h5>{i18n.t("admin_settings")}</h5>
202         <form onSubmit={linkEvent(this, this.handleSiteConfigSubmit)}>
203           <div class="form-group row">
204             <label
205               class="col-12 col-form-label"
206               htmlFor={this.siteConfigTextAreaId}
207             >
208               {i18n.t("site_config")}
209             </label>
210             <div class="col-12">
211               <textarea
212                 id={this.siteConfigTextAreaId}
213                 value={this.state.siteConfigHjson}
214                 onInput={linkEvent(this, this.handleSiteConfigHjsonChange)}
215                 class="form-control text-monospace"
216                 rows={3}
217               />
218             </div>
219           </div>
220           <div class="form-group row">
221             <div class="col-12">
222               <button type="submit" class="btn btn-secondary mr-2">
223                 {this.state.siteConfigLoading ? (
224                   <Spinner />
225                 ) : (
226                   capitalizeFirstLetter(i18n.t("save"))
227                 )}
228               </button>
229             </div>
230           </div>
231         </form>
232       </div>
233     );
234   }
235
236   handleSiteConfigSubmit(i: AdminSettings, event: any) {
237     event.preventDefault();
238     i.state.siteConfigLoading = true;
239     let form: SaveSiteConfig = {
240       config_hjson: i.state.siteConfigHjson,
241       auth: authField(),
242     };
243     WebSocketService.Instance.send(wsClient.saveSiteConfig(form));
244     i.setState(i.state);
245   }
246
247   handleSiteConfigHjsonChange(i: AdminSettings, event: any) {
248     i.state.siteConfigHjson = event.target.value;
249     i.setState(i.state);
250   }
251
252   handleLeaveAdminTeam(i: AdminSettings) {
253     i.state.leaveAdminTeamLoading = true;
254     WebSocketService.Instance.send(wsClient.leaveAdmin({ auth: authField() }));
255     i.setState(i.state);
256   }
257
258   parseMessage(msg: any) {
259     let op = wsUserOp(msg);
260     console.log(msg);
261     if (msg.error) {
262       toast(i18n.t(msg.error), "danger");
263       this.context.router.history.push("/");
264       this.state.loading = false;
265       this.setState(this.state);
266       return;
267     } else if (op == UserOperation.EditSite) {
268       let data = wsJsonToRes<SiteResponse>(msg).data;
269       this.state.siteRes.site_view = data.site_view;
270       this.setState(this.state);
271       toast(i18n.t("site_saved"));
272     } else if (op == UserOperation.GetBannedPersons) {
273       let data = wsJsonToRes<BannedPersonsResponse>(msg).data;
274       this.state.banned = data.banned;
275       this.setState(this.state);
276     } else if (op == UserOperation.GetSiteConfig) {
277       let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
278       this.state.siteConfigRes = data;
279       this.state.loading = false;
280       this.state.siteConfigHjson = this.state.siteConfigRes.config_hjson;
281       this.setState(this.state);
282       var textarea: any = document.getElementById(this.siteConfigTextAreaId);
283       autosize(textarea);
284     } else if (op == UserOperation.LeaveAdmin) {
285       let data = wsJsonToRes<GetSiteResponse>(msg).data;
286       this.state.siteRes.site_view = data.site_view;
287       this.setState(this.state);
288       this.state.leaveAdminTeamLoading = false;
289       toast(i18n.t("left_admin_team"));
290       this.setState(this.state);
291       this.context.router.history.push("/");
292     } else if (op == UserOperation.SaveSiteConfig) {
293       let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
294       this.state.siteConfigRes = data;
295       this.state.siteConfigHjson = this.state.siteConfigRes.config_hjson;
296       this.state.siteConfigLoading = false;
297       toast(i18n.t("site_saved"));
298       this.setState(this.state);
299     }
300   }
301 }