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