]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/admin-settings.tsx
Merge pull request #1031 from SleeplessOne1917/rate-limiting-tab
[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   GetFederatedInstancesResponse,
7   GetSiteResponse,
8   PersonView,
9   SiteResponse,
10   UserOperation,
11   wsJsonToRes,
12   wsUserOp,
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   capitalizeFirstLetter,
20   isBrowser,
21   myAuth,
22   randomStr,
23   setIsoData,
24   showLocal,
25   toast,
26   wsClient,
27   wsSubscribe,
28 } from "../../utils";
29 import { HtmlTags } from "../common/html-tags";
30 import { Spinner } from "../common/icon";
31 import Tabs from "../common/tabs";
32 import { PersonListing } from "../person/person-listing";
33 import { EmojiForm } from "./emojis-form";
34 import RateLimitForm from "./rate-limit-form";
35 import { SiteForm } from "./site-form";
36 import { TaglineForm } from "./tagline-form";
37
38 interface AdminSettingsState {
39   siteRes: GetSiteResponse;
40   instancesRes?: GetFederatedInstancesResponse;
41   banned: PersonView[];
42   loading: 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   state: AdminSettingsState = {
51     siteRes: this.isoData.site_res,
52     banned: [],
53     loading: true,
54     leaveAdminTeamLoading: false,
55   };
56
57   constructor(props: any, context: any) {
58     super(props, context);
59
60     this.parseMessage = this.parseMessage.bind(this);
61     this.subscription = wsSubscribe(this.parseMessage);
62
63     // Only fetch the data if coming from another route
64     if (this.isoData.path == this.context.router.route.match.url) {
65       this.state = {
66         ...this.state,
67         banned: (this.isoData.routeData[0] as BannedPersonsResponse).banned,
68         instancesRes: this.isoData
69           .routeData[1] as GetFederatedInstancesResponse,
70         loading: false,
71       };
72     } else {
73       let cAuth = myAuth();
74       if (cAuth) {
75         WebSocketService.Instance.send(
76           wsClient.getBannedPersons({
77             auth: cAuth,
78           })
79         );
80         WebSocketService.Instance.send(
81           wsClient.getFederatedInstances({ auth: cAuth })
82         );
83       }
84     }
85   }
86
87   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
88     let promises: Promise<any>[] = [];
89
90     let auth = req.auth;
91     if (auth) {
92       let bannedPersonsForm: GetBannedPersons = { auth };
93       promises.push(req.client.getBannedPersons(bannedPersonsForm));
94       promises.push(req.client.getFederatedInstances({ auth }));
95     }
96
97     return promises;
98   }
99
100   componentDidMount() {
101     if (isBrowser()) {
102       var textarea: any = document.getElementById(this.siteConfigTextAreaId);
103       autosize(textarea);
104     }
105   }
106
107   componentWillUnmount() {
108     if (isBrowser()) {
109       this.subscription?.unsubscribe();
110     }
111   }
112
113   get documentTitle(): string {
114     return `${i18n.t("admin_settings")} - ${
115       this.state.siteRes.site_view.site.name
116     }`;
117   }
118
119   render() {
120     return (
121       <div className="container-lg">
122         <HtmlTags
123           title={this.documentTitle}
124           path={this.context.router.route.match.url}
125         />
126         {this.state.loading ? (
127           <h5>
128             <Spinner large />
129           </h5>
130         ) : (
131           <Tabs
132             tabs={[
133               {
134                 key: "site",
135                 label: i18n.t("site"),
136                 getNode: () => (
137                   <div className="row">
138                     <div className="col-12 col-md-6">
139                       <SiteForm
140                         siteRes={this.state.siteRes}
141                         instancesRes={this.state.instancesRes}
142                         showLocal={showLocal(this.isoData)}
143                       />
144                     </div>
145                     <div className="col-12 col-md-6">
146                       {this.admins()}
147                       {this.bannedUsers()}
148                     </div>
149                   </div>
150                 ),
151               },
152               {
153                 key: "rate_limiting",
154                 label: "Rate Limiting",
155                 getNode: () => (
156                   <RateLimitForm
157                     localSiteRateLimit={
158                       this.state.siteRes.site_view.local_site_rate_limit
159                     }
160                     applicationQuestion={
161                       this.state.siteRes.site_view.local_site
162                         .application_question
163                     }
164                   />
165                 ),
166               },
167               {
168                 key: "taglines",
169                 label: i18n.t("taglines"),
170                 getNode: () => (
171                   <div className="row">
172                     <TaglineForm siteRes={this.state.siteRes} />
173                   </div>
174                 ),
175               },
176               {
177                 key: "emojis",
178                 label: i18n.t("emojis"),
179                 getNode: () => (
180                   <div className="row">
181                     <EmojiForm />
182                   </div>
183                 ),
184               },
185             ]}
186           />
187         )}
188       </div>
189     );
190   }
191
192   admins() {
193     return (
194       <>
195         <h5>{capitalizeFirstLetter(i18n.t("admins"))}</h5>
196         <ul className="list-unstyled">
197           {this.state.siteRes.admins.map(admin => (
198             <li key={admin.person.id} className="list-inline-item">
199               <PersonListing person={admin.person} />
200             </li>
201           ))}
202         </ul>
203         {this.leaveAdmin()}
204       </>
205     );
206   }
207
208   leaveAdmin() {
209     return (
210       <button
211         onClick={linkEvent(this, this.handleLeaveAdminTeam)}
212         className="btn btn-danger mb-2"
213       >
214         {this.state.leaveAdminTeamLoading ? (
215           <Spinner />
216         ) : (
217           i18n.t("leave_admin_team")
218         )}
219       </button>
220     );
221   }
222
223   bannedUsers() {
224     return (
225       <>
226         <h5>{i18n.t("banned_users")}</h5>
227         <ul className="list-unstyled">
228           {this.state.banned.map(banned => (
229             <li key={banned.person.id} className="list-inline-item">
230               <PersonListing person={banned.person} />
231             </li>
232           ))}
233         </ul>
234       </>
235     );
236   }
237
238   handleLeaveAdminTeam(i: AdminSettings) {
239     let auth = myAuth();
240     if (auth) {
241       i.setState({ leaveAdminTeamLoading: true });
242       WebSocketService.Instance.send(wsClient.leaveAdmin({ auth }));
243     }
244   }
245
246   parseMessage(msg: any) {
247     let op = wsUserOp(msg);
248     console.log(msg);
249     if (msg.error) {
250       toast(i18n.t(msg.error), "danger");
251       this.context.router.history.push("/");
252       this.setState({ loading: false });
253       return;
254     } else if (op == UserOperation.EditSite) {
255       let data = wsJsonToRes<SiteResponse>(msg);
256       this.setState(s => ((s.siteRes.site_view = data.site_view), s));
257       toast(i18n.t("site_saved"));
258     } else if (op == UserOperation.GetBannedPersons) {
259       let data = wsJsonToRes<BannedPersonsResponse>(msg);
260       this.setState({ banned: data.banned, loading: false });
261     } else if (op == UserOperation.LeaveAdmin) {
262       let data = wsJsonToRes<GetSiteResponse>(msg);
263       this.setState(s => ((s.siteRes.site_view = data.site_view), s));
264       this.setState({ leaveAdminTeamLoading: false });
265       toast(i18n.t("left_admin_team"));
266       this.context.router.history.push("/");
267     } else if (op == UserOperation.GetFederatedInstances) {
268       let data = wsJsonToRes<GetFederatedInstancesResponse>(msg);
269       this.setState({ instancesRes: data });
270     }
271   }
272 }