Skip to content

Commit

Permalink
Private instances (#523)
Browse files Browse the repository at this point in the history
* Updating translations.

* Adding registration applications.

* Updating translations.

* Adding verify email route.

* Fix missing signup question bug.

* Updating translations.

* A few fixes from comments on lemmy PR.

* v0.15.0-rc.4

* Some suggestions from PR.

* v0.15.0-rc.5

* Adding optional auth to modlog fetches.

* v0.15.0-rc.6

* Hide deny / approve buttons
  • Loading branch information
dessalines authored Dec 30, 2021
1 parent 4c6713d commit b96e16b
Show file tree
Hide file tree
Showing 23 changed files with 849 additions and 65 deletions.
2 changes: 1 addition & 1 deletion lemmy-translations
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "lemmy-ui",
"description": "An isomorphic UI for lemmy",
"version": "0.14.5",
"version": "0.15.0-rc.6",
"author": "Dessalines <[email protected]>",
"license": "AGPL-3.0",
"scripts": {
Expand Down Expand Up @@ -72,7 +72,7 @@
"husky": "^7.0.4",
"import-sort-style-module": "^6.0.0",
"iso-639-1": "^2.1.10",
"lemmy-js-client": "0.14.0-rc.1",
"lemmy-js-client": "0.15.0-rc.6",
"lint-staged": "^12.1.2",
"mini-css-extract-plugin": "^2.4.5",
"node-fetch": "^2.6.1",
Expand Down
6 changes: 5 additions & 1 deletion src/server/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ server.get("/*", async (req, res) => {
if (routeData[0] && routeData[0].error) {
let errCode = routeData[0].error;
console.error(errCode);
return res.redirect(`/404?err=${errCode}`);
if (errCode == "instance_is_private") {
return res.redirect(`/signup`);
} else {
return res.redirect(`/404?err=${errCode}`);
}
}

let isoData: IsoData = {
Expand Down
86 changes: 84 additions & 2 deletions src/shared/components/app/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
GetSiteResponse,
GetUnreadCount,
GetUnreadCountResponse,
GetUnreadRegistrationApplicationCount,
GetUnreadRegistrationApplicationCountResponse,
PrivateMessageResponse,
UserOperation,
} from "lemmy-js-client";
Expand Down Expand Up @@ -41,6 +43,7 @@ interface NavbarState {
expanded: boolean;
unreadInboxCount: number;
unreadReportCount: number;
unreadApplicationCount: number;
searchParam: string;
toggleSearch: boolean;
showDropdown: boolean;
Expand All @@ -52,11 +55,13 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
private userSub: Subscription;
private unreadInboxCountSub: Subscription;
private unreadReportCountSub: Subscription;
private unreadApplicationCountSub: Subscription;
private searchTextField: RefObject<HTMLInputElement>;
emptyState: NavbarState = {
isLoggedIn: !!this.props.site_res.my_user,
unreadInboxCount: 0,
unreadReportCount: 0,
unreadApplicationCount: 0,
expanded: false,
searchParam: "",
toggleSearch: false,
Expand Down Expand Up @@ -115,6 +120,11 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
UserService.Instance.unreadReportCountSub.subscribe(res => {
this.setState({ unreadReportCount: res });
});
// Subscribe to unread application count
this.unreadApplicationCountSub =
UserService.Instance.unreadApplicationCountSub.subscribe(res => {
this.setState({ unreadApplicationCount: res });
});
}
}

Expand All @@ -123,6 +133,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
this.userSub.unsubscribe();
this.unreadInboxCountSub.unsubscribe();
this.unreadReportCountSub.unsubscribe();
this.unreadApplicationCountSub.unsubscribe();
}

updateUrl() {
Expand Down Expand Up @@ -215,6 +226,31 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
</li>
</ul>
)}
{UserService.Instance.myUserInfo?.local_user_view.person
.admin && (
<ul class="navbar-nav ml-1">
<li className="nav-item">
<NavLink
to="/registration_applications"
className="p-1 navbar-toggler nav-link border-0"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_registration_applications", {
count: this.state.unreadApplicationCount,
formattedCount: numToSI(
this.state.unreadApplicationCount
),
})}
>
<Icon icon="clipboard" />
{this.state.unreadApplicationCount > 0 && (
<span class="mx-1 badge badge-light">
{numToSI(this.state.unreadApplicationCount)}
</span>
)}
</NavLink>
</li>
</ul>
)}
</>
)}
<button
Expand Down Expand Up @@ -366,6 +402,31 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
</li>
</ul>
)}
{UserService.Instance.myUserInfo?.local_user_view.person
.admin && (
<ul class="navbar-nav my-2">
<li className="nav-item">
<NavLink
to="/registration_applications"
className="nav-link"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
title={i18n.t("unread_registration_applications", {
count: this.state.unreadApplicationCount,
formattedCount: numToSI(
this.state.unreadApplicationCount
),
})}
>
<Icon icon="clipboard" />
{this.state.unreadApplicationCount > 0 && (
<span class="mx-1 badge badge-light">
{numToSI(this.state.unreadApplicationCount)}
</span>
)}
</NavLink>
</li>
</ul>
)}
<ul class="navbar-nav">
<li class="nav-item dropdown">
<button
Expand Down Expand Up @@ -537,6 +598,12 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
this.state.unreadReportCount = data.post_reports + data.comment_reports;
this.setState(this.state);
this.sendReportUnread();
} else if (op == UserOperation.GetUnreadRegistrationApplicationCount) {
let data =
wsJsonToRes<GetUnreadRegistrationApplicationCountResponse>(msg).data;
this.state.unreadApplicationCount = data.registration_applications;
this.setState(this.state);
this.sendApplicationUnread();
} else if (op == UserOperation.GetSite) {
// This is only called on a successful login
let data = wsJsonToRes<GetSiteResponse>(msg).data;
Expand Down Expand Up @@ -586,16 +653,25 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
let unreadForm: GetUnreadCount = {
auth: authField(),
};

WebSocketService.Instance.send(wsClient.getUnreadCount(unreadForm));

console.log("Fetching reports...");

let reportCountForm: GetReportCount = {
auth: authField(),
};

WebSocketService.Instance.send(wsClient.getReportCount(reportCountForm));

if (UserService.Instance.myUserInfo?.local_user_view.person.admin) {
console.log("Fetching applications...");

let applicationCountForm: GetUnreadRegistrationApplicationCount = {
auth: authField(),
};
WebSocketService.Instance.send(
wsClient.getUnreadRegistrationApplicationCount(applicationCountForm)
);
}
}

get currentLocation() {
Expand All @@ -612,6 +688,12 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
);
}

sendApplicationUnread() {
UserService.Instance.unreadApplicationCountSub.next(
this.state.unreadApplicationCount
);
}

get canAdmin(): boolean {
return (
UserService.Instance.myUserInfo &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export class CommentReport extends Component<CommentReportProps, any> {
render() {
let r = this.props.report;
let comment = r.comment;
let tippyContent = i18n.t(
r.comment_report.resolved ? "unresolve_report" : "resolve_report"
);

// Set the original post data ( a troll could change it )
comment.content = r.comment_report.original_comment_text;
Expand Down Expand Up @@ -78,12 +81,8 @@ export class CommentReport extends Component<CommentReportProps, any> {
<button
className="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleResolveReport)}
data-tippy-content={
r.comment_report.resolved ? "unresolve_report" : "resolve_report"
}
aria-label={
r.comment_report.resolved ? "unresolve_report" : "resolve_report"
}
data-tippy-content={tippyContent}
aria-label={tippyContent}
>
<Icon
icon="check"
Expand Down
2 changes: 1 addition & 1 deletion src/shared/components/common/markdown-textarea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import { Icon, Spinner } from "./icon";

interface MarkdownTextAreaProps {
initialContent: string;
initialContent?: string;
finished?: boolean;
buttonTitle?: string;
replyType?: boolean;
Expand Down
150 changes: 150 additions & 0 deletions src/shared/components/common/registration-application.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
ApproveRegistrationApplication,
RegistrationApplicationView,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { WebSocketService } from "../../services";
import { authField, mdToHtml, wsClient } from "../../utils";
import { PersonListing } from "../person/person-listing";
import { MarkdownTextArea } from "./markdown-textarea";
import { MomentTime } from "./moment-time";

interface RegistrationApplicationProps {
application: RegistrationApplicationView;
}

interface RegistrationApplicationState {
denyReason?: string;
denyExpanded: boolean;
}

export class RegistrationApplication extends Component<
RegistrationApplicationProps,
RegistrationApplicationState
> {
private emptyState: RegistrationApplicationState = {
denyReason: this.props.application.registration_application.deny_reason,
denyExpanded: false,
};

constructor(props: any, context: any) {
super(props, context);

this.state = this.emptyState;
this.handleDenyReasonChange = this.handleDenyReasonChange.bind(this);
}

render() {
let a = this.props.application;
let ra = this.props.application.registration_application;
let accepted = a.creator_local_user.accepted_application;

return (
<div>
<div>
{i18n.t("applicant")}: <PersonListing person={a.creator} />
</div>
<div>
{i18n.t("created")}: <MomentTime showAgo data={ra} />
</div>
<div>{i18n.t("answer")}:</div>
<div className="md-div" dangerouslySetInnerHTML={mdToHtml(ra.answer)} />

{a.admin && (
<div>
{accepted ? (
<T i18nKey="approved_by">
#
<PersonListing person={a.admin} />
</T>
) : (
<div>
<T i18nKey="denied_by">
#
<PersonListing person={a.admin} />
</T>
<div>
{i18n.t("deny_reason")}:{" "}
<div
className="md-div d-inline-flex"
dangerouslySetInnerHTML={mdToHtml(ra.deny_reason || "")}
/>
</div>
</div>
)}
</div>
)}

{this.state.denyExpanded && (
<div class="form-group row">
<label class="col-sm-2 col-form-label">
{i18n.t("deny_reason")}
</label>
<div class="col-sm-10">
<MarkdownTextArea
initialContent={this.state.denyReason}
onContentChange={this.handleDenyReasonChange}
hideNavigationWarnings
/>
</div>
</div>
)}
{(!ra.admin_id || (ra.admin_id && !accepted)) && (
<button
className="btn btn-secondary mr-2 my-2"
onClick={linkEvent(this, this.handleApprove)}
aria-label={i18n.t("approve")}
>
{i18n.t("approve")}
</button>
)}
{(!ra.admin_id || (ra.admin_id && accepted)) && (
<button
className="btn btn-secondary mr-2"
onClick={linkEvent(this, this.handleDeny)}
aria-label={i18n.t("deny")}
>
{i18n.t("deny")}
</button>
)}
</div>
);
}

handleApprove(i: RegistrationApplication) {
i.setState({ denyExpanded: false });
let form: ApproveRegistrationApplication = {
id: i.props.application.registration_application.id,
deny_reason: "",
approve: true,
auth: authField(),
};
WebSocketService.Instance.send(
wsClient.approveRegistrationApplication(form)
);
}

handleDeny(i: RegistrationApplication) {
if (i.state.denyExpanded) {
i.setState({ denyExpanded: false });
let form: ApproveRegistrationApplication = {
id: i.props.application.registration_application.id,
approve: false,
deny_reason: i.state.denyReason,
auth: authField(),
};
WebSocketService.Instance.send(
wsClient.approveRegistrationApplication(form)
);
} else {
i.setState({ denyExpanded: true });
}
}

handleDenyReasonChange(val: string) {
this.state.denyReason = val;
this.setState(this.state);
}
}
3 changes: 3 additions & 0 deletions src/shared/components/common/symbols.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export const SYMBOLS = (
xmlnsXlink="http://www.w3.org/1999/xlink"
>
<defs>
<symbol id="icon-clipboard" viewBox="0 0 24 24">
<path d="M7 5c0 0.552 0.225 1.053 0.586 1.414s0.862 0.586 1.414 0.586h6c0.552 0 1.053-0.225 1.414-0.586s0.586-0.862 0.586-1.414h1c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v14c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-12c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-14c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293zM9 1c-0.552 0-1.053 0.225-1.414 0.586s-0.586 0.862-0.586 1.414h-1c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v14c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h12c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-14c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879h-1c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586zM9 3h6v2h-6z"></path>
</symbol>
<symbol id="icon-shield" viewBox="0 0 24 24">
<path d="M12 20.862c-1.184-0.672-4.42-2.695-6.050-5.549-0.079-0.138-0.153-0.276-0.223-0.417-0.456-0.911-0.727-1.878-0.727-2.896v-6.307l7-2.625 7 2.625v6.307c0 1.018-0.271 1.985-0.726 2.897-0.070 0.14-0.145 0.279-0.223 0.417-1.631 2.854-4.867 4.876-6.050 5.549zM12.447 22.894c0 0 4.989-2.475 7.34-6.589 0.096-0.168 0.188-0.34 0.276-0.515 0.568-1.135 0.937-2.408 0.937-3.79v-7c0-0.426-0.267-0.79-0.649-0.936l-8-3c-0.236-0.089-0.485-0.082-0.702 0l-8 3c-0.399 0.149-0.646 0.527-0.649 0.936v7c0 1.382 0.369 2.655 0.938 3.791 0.087 0.175 0.179 0.346 0.276 0.515 2.351 4.114 7.34 6.589 7.34 6.589 0.292 0.146 0.62 0.136 0.894 0z"></path>
</symbol>
Expand Down
Loading

0 comments on commit b96e16b

Please sign in to comment.