Merge pull request #221 from LemmyNet/split_user_table

user_ -> person table migration.
This commit is contained in:
Dessalines 2021-03-25 11:42:46 -04:00 committed by GitHub
commit 7ddcac5fc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 631 additions and 526 deletions

@ -1 +1 @@
Subproject commit a15d6bcb944b63478e9499ca77d6023a675cb002 Subproject commit 4b82eeaaf4762e7a282548b675f40352c1f5ef33

View file

@ -67,7 +67,8 @@
"eslint": "^7.20.0", "eslint": "^7.20.0",
"eslint-plugin-prettier": "^3.3.1", "eslint-plugin-prettier": "^3.3.1",
"husky": "^5.1.0", "husky": "^5.1.0",
"lemmy-js-client": "0.10.0-rc.1", "iso-639-1": "^2.1.9",
"lemmy-js-client": "0.10.0-rc.10",
"lint-staged": "^10.5.4", "lint-staged": "^10.5.4",
"mini-css-extract-plugin": "^1.3.8", "mini-css-extract-plugin": "^1.3.8",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",

View file

@ -12,7 +12,7 @@ import {
} from "../shared/interfaces"; } from "../shared/interfaces";
import { routes } from "../shared/routes"; import { routes } from "../shared/routes";
import IsomorphicCookie from "isomorphic-cookie"; import IsomorphicCookie from "isomorphic-cookie";
import { GetSite, LemmyHttp } from "lemmy-js-client"; import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client";
import process from "process"; import process from "process";
import { Helmet } from "inferno-helmet"; import { Helmet } from "inferno-helmet";
import { initializeSite } from "../shared/initialize"; import { initializeSite } from "../shared/initialize";
@ -48,7 +48,18 @@ server.get("/*", async (req, res) => {
}; };
// Get site data first // Get site data first
let site = await initialFetchReq.client.getSite(getSiteForm); // This bypasses errors, so that the client can hit the error on its own,
// in order to remove the jwt on the browser. Necessary for wrong jwts
let try_site: any = await initialFetchReq.client.getSite(getSiteForm);
if (try_site.error == "not_logged_in") {
console.error(
"Incorrect JWT token, skipping auth so frontend can remove jwt cookie"
);
delete getSiteForm.auth;
delete initialFetchReq.auth;
try_site = await initialFetchReq.client.getSite(getSiteForm);
}
let site: GetSiteResponse = try_site;
initializeSite(site); initializeSite(site);
if (activeRoute.fetchInitialData) { if (activeRoute.fetchInitialData) {
@ -67,7 +78,7 @@ server.get("/*", async (req, res) => {
? req.headers["accept-language"].split(",")[0] ? req.headers["accept-language"].split(",")[0]
: "en"; : "en";
let lang = site.my_user let lang = site.my_user
? site.my_user.lang == "browser" ? site.my_user.local_user.lang == "browser"
? acceptLang ? acceptLang
: "en" : "en"
: acceptLang; : acceptLang;

View file

@ -23,7 +23,7 @@ import {
} from "../utils"; } from "../utils";
import autosize from "autosize"; import autosize from "autosize";
import { SiteForm } from "./site-form"; import { SiteForm } from "./site-form";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { HtmlTags } from "./html-tags"; import { HtmlTags } from "./html-tags";
import { Spinner } from "./icon"; import { Spinner } from "./icon";
import { i18n } from "../i18next"; import { i18n } from "../i18next";
@ -135,7 +135,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
<ul class="list-unstyled"> <ul class="list-unstyled">
{this.state.siteRes.admins.map(admin => ( {this.state.siteRes.admins.map(admin => (
<li class="list-inline-item"> <li class="list-inline-item">
<UserListing user={admin.user} /> <PersonListing person={admin.person} />
</li> </li>
))} ))}
</ul> </ul>
@ -150,7 +150,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
<ul class="list-unstyled"> <ul class="list-unstyled">
{this.state.siteRes.banned.map(banned => ( {this.state.siteRes.banned.map(banned => (
<li class="list-inline-item"> <li class="list-inline-item">
<UserListing user={banned.user} /> <PersonListing person={banned.person} />
</li> </li>
))} ))}
</ul> </ul>

View file

@ -26,7 +26,7 @@ export class App extends Component<AppProps, any> {
<> <>
<Provider i18next={i18n}> <Provider i18next={i18n}>
<div> <div>
<Theme user={siteRes.my_user} /> <Theme localUserView={siteRes.my_user} />
{siteRes && {siteRes &&
siteRes.site_view && siteRes.site_view &&
this.props.siteRes.site_view.site.icon && ( this.props.siteRes.site_view.site.icon && (

View file

@ -68,7 +68,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
render() { render() {
return ( return (
<div class="mb-3"> <div class="mb-3">
{UserService.Instance.user ? ( {UserService.Instance.localUserView ? (
<MarkdownTextArea <MarkdownTextArea
initialContent={ initialContent={
this.props.edit this.props.edit
@ -133,7 +133,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
let op = wsUserOp(msg); let op = wsUserOp(msg);
// Only do the showing and hiding if logged in // Only do the showing and hiding if logged in
if (UserService.Instance.user) { if (UserService.Instance.localUserView) {
if ( if (
op == UserOperation.CreateComment || op == UserOperation.CreateComment ||
op == UserOperation.EditComment op == UserOperation.EditComment

View file

@ -5,18 +5,18 @@ import {
DeleteComment, DeleteComment,
RemoveComment, RemoveComment,
MarkCommentAsRead, MarkCommentAsRead,
MarkUserMentionAsRead, MarkPersonMentionAsRead,
SaveComment, SaveComment,
BanFromCommunity, BanFromCommunity,
BanUser, BanPerson,
CommunityModeratorView, CommunityModeratorView,
UserViewSafe, PersonViewSafe,
AddModToCommunity, AddModToCommunity,
AddAdmin, AddAdmin,
TransferCommunity, TransferCommunity,
TransferSite, TransferSite,
CommentView, CommentView,
UserMentionView, PersonMentionView,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { CommentNode as CommentNodeI, BanType } from "../interfaces"; import { CommentNode as CommentNodeI, BanType } from "../interfaces";
import { WebSocketService, UserService } from "../services"; import { WebSocketService, UserService } from "../services";
@ -34,7 +34,7 @@ import moment from "moment";
import { MomentTime } from "./moment-time"; import { MomentTime } from "./moment-time";
import { CommentForm } from "./comment-form"; import { CommentForm } from "./comment-form";
import { CommentNodes } from "./comment-nodes"; import { CommentNodes } from "./comment-nodes";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
import { Icon, Spinner } from "./icon"; import { Icon, Spinner } from "./icon";
import { i18n } from "../i18next"; import { i18n } from "../i18next";
@ -74,7 +74,7 @@ interface CommentNodeProps {
markable?: boolean; markable?: boolean;
showContext?: boolean; showContext?: boolean;
moderators: CommunityModeratorView[]; moderators: CommunityModeratorView[];
admins: UserViewSafe[]; admins: PersonViewSafe[];
// TODO is this necessary, can't I get it from the node itself? // TODO is this necessary, can't I get it from the node itself?
postCreatorId?: number; postCreatorId?: number;
showCommunity?: boolean; showCommunity?: boolean;
@ -156,7 +156,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
> >
<div class="d-flex flex-wrap align-items-center text-muted small"> <div class="d-flex flex-wrap align-items-center text-muted small">
<span class="mr-2"> <span class="mr-2">
<UserListing user={cv.creator} /> <PersonListing person={cv.creator} />
</span> </span>
{this.isMod && ( {this.isMod && (
@ -270,7 +270,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)} )}
</button> </button>
)} )}
{UserService.Instance.user && !this.props.viewOnly && ( {UserService.Instance.localUserView && !this.props.viewOnly && (
<> <>
<button <button
className={`btn btn-link btn-animate ${ className={`btn btn-link btn-animate ${
@ -791,7 +791,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
get commentOrMentionRead() { get commentOrMentionRead() {
let cv = this.props.node.comment_view; let cv = this.props.node.comment_view;
return this.isUserMentionType(cv) ? cv.user_mention.read : cv.comment.read; return this.isPersonMentionType(cv)
? cv.person_mention.read
: cv.comment.read;
} }
get linkBtn() { get linkBtn() {
@ -813,8 +815,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
get myComment(): boolean { get myComment(): boolean {
return ( return (
UserService.Instance.user && this.props.node.comment_view.creator.id ==
this.props.node.comment_view.creator.id == UserService.Instance.user.id UserService.Instance.localUserView?.person.id
); );
} }
@ -832,7 +834,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
return ( return (
this.props.admins && this.props.admins &&
isMod( isMod(
this.props.admins.map(a => a.user.id), this.props.admins.map(a => a.person.id),
this.props.node.comment_view.creator.id this.props.node.comment_view.creator.id
) )
); );
@ -845,11 +847,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
get canMod(): boolean { get canMod(): boolean {
if (this.props.admins && this.props.moderators) { if (this.props.admins && this.props.moderators) {
let adminsThenMods = this.props.admins let adminsThenMods = this.props.admins
.map(a => a.user.id) .map(a => a.person.id)
.concat(this.props.moderators.map(m => m.moderator.id)); .concat(this.props.moderators.map(m => m.moderator.id));
return canMod( return canMod(
UserService.Instance.user, UserService.Instance.localUserView,
adminsThenMods, adminsThenMods,
this.props.node.comment_view.creator.id this.props.node.comment_view.creator.id
); );
@ -862,8 +864,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
return ( return (
this.props.admins && this.props.admins &&
canMod( canMod(
UserService.Instance.user, UserService.Instance.localUserView,
this.props.admins.map(a => a.user.id), this.props.admins.map(a => a.person.id),
this.props.node.comment_view.creator.id this.props.node.comment_view.creator.id
) )
); );
@ -872,18 +874,22 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
get amCommunityCreator(): boolean { get amCommunityCreator(): boolean {
return ( return (
this.props.moderators && this.props.moderators &&
UserService.Instance.user && UserService.Instance.localUserView &&
this.props.node.comment_view.creator.id != UserService.Instance.user.id && this.props.node.comment_view.creator.id !=
UserService.Instance.user.id == this.props.moderators[0].moderator.id UserService.Instance.localUserView.person.id &&
UserService.Instance.localUserView.person.id ==
this.props.moderators[0].moderator.id
); );
} }
get amSiteCreator(): boolean { get amSiteCreator(): boolean {
return ( return (
this.props.admins && this.props.admins &&
UserService.Instance.user && UserService.Instance.localUserView &&
this.props.node.comment_view.creator.id != UserService.Instance.user.id && this.props.node.comment_view.creator.id !=
UserService.Instance.user.id == this.props.admins[0].user.id UserService.Instance.localUserView.person.id &&
UserService.Instance.localUserView.person.id ==
this.props.admins[0].person.id
); );
} }
@ -1024,20 +1030,20 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
i.setState(i.state); i.setState(i.state);
} }
isUserMentionType( isPersonMentionType(
item: CommentView | UserMentionView item: CommentView | PersonMentionView
): item is UserMentionView { ): item is PersonMentionView {
return (item as UserMentionView).user_mention?.id !== undefined; return (item as PersonMentionView).person_mention?.id !== undefined;
} }
handleMarkRead(i: CommentNode) { handleMarkRead(i: CommentNode) {
if (i.isUserMentionType(i.props.node.comment_view)) { if (i.isPersonMentionType(i.props.node.comment_view)) {
let form: MarkUserMentionAsRead = { let form: MarkPersonMentionAsRead = {
user_mention_id: i.props.node.comment_view.user_mention.id, person_mention_id: i.props.node.comment_view.person_mention.id,
read: !i.props.node.comment_view.user_mention.read, read: !i.props.node.comment_view.person_mention.read,
auth: authField(), auth: authField(),
}; };
WebSocketService.Instance.send(wsClient.markUserMentionAsRead(form)); WebSocketService.Instance.send(wsClient.markPersonMentionAsRead(form));
} else { } else {
let form: MarkCommentAsRead = { let form: MarkCommentAsRead = {
comment_id: i.props.node.comment_view.comment.id, comment_id: i.props.node.comment_view.comment.id,
@ -1095,7 +1101,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
i.state.removeData = false; i.state.removeData = false;
} }
let form: BanFromCommunity = { let form: BanFromCommunity = {
user_id: cv.creator.id, person_id: cv.creator.id,
community_id: cv.community.id, community_id: cv.community.id,
ban, ban,
remove_data: i.state.removeData, remove_data: i.state.removeData,
@ -1110,15 +1116,15 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
if (ban == false) { if (ban == false) {
i.state.removeData = false; i.state.removeData = false;
} }
let form: BanUser = { let form: BanPerson = {
user_id: cv.creator.id, person_id: cv.creator.id,
ban, ban,
remove_data: i.state.removeData, remove_data: i.state.removeData,
reason: i.state.banReason, reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires), expires: getUnixTime(i.state.banExpires),
auth: authField(), auth: authField(),
}; };
WebSocketService.Instance.send(wsClient.banUser(form)); WebSocketService.Instance.send(wsClient.banPerson(form));
} }
i.state.showBanDialog = false; i.state.showBanDialog = false;
@ -1138,7 +1144,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
handleAddModToCommunity(i: CommentNode) { handleAddModToCommunity(i: CommentNode) {
let cv = i.props.node.comment_view; let cv = i.props.node.comment_view;
let form: AddModToCommunity = { let form: AddModToCommunity = {
user_id: cv.creator.id, person_id: cv.creator.id,
community_id: cv.community.id, community_id: cv.community.id,
added: !i.isMod, added: !i.isMod,
auth: authField(), auth: authField(),
@ -1160,7 +1166,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
handleAddAdmin(i: CommentNode) { handleAddAdmin(i: CommentNode) {
let form: AddAdmin = { let form: AddAdmin = {
user_id: i.props.node.comment_view.creator.id, person_id: i.props.node.comment_view.creator.id,
added: !i.isAdmin, added: !i.isAdmin,
auth: authField(), auth: authField(),
}; };
@ -1183,7 +1189,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
let cv = i.props.node.comment_view; let cv = i.props.node.comment_view;
let form: TransferCommunity = { let form: TransferCommunity = {
community_id: cv.community.id, community_id: cv.community.id,
user_id: cv.creator.id, person_id: cv.creator.id,
auth: authField(), auth: authField(),
}; };
WebSocketService.Instance.send(wsClient.transferCommunity(form)); WebSocketService.Instance.send(wsClient.transferCommunity(form));
@ -1203,7 +1209,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
handleTransferSite(i: CommentNode) { handleTransferSite(i: CommentNode) {
let form: TransferSite = { let form: TransferSite = {
user_id: i.props.node.comment_view.creator.id, person_id: i.props.node.comment_view.creator.id,
auth: authField(), auth: authField(),
}; };
WebSocketService.Instance.send(wsClient.transferSite(form)); WebSocketService.Instance.send(wsClient.transferSite(form));

View file

@ -1,12 +1,12 @@
import { Component } from "inferno"; import { Component } from "inferno";
import { CommentNode as CommentNodeI } from "../interfaces"; import { CommentNode as CommentNodeI } from "../interfaces";
import { CommunityModeratorView, UserViewSafe } from "lemmy-js-client"; import { CommunityModeratorView, PersonViewSafe } from "lemmy-js-client";
import { CommentNode } from "./comment-node"; import { CommentNode } from "./comment-node";
interface CommentNodesProps { interface CommentNodesProps {
nodes: CommentNodeI[]; nodes: CommentNodeI[];
moderators?: CommunityModeratorView[]; moderators?: CommunityModeratorView[];
admins?: UserViewSafe[]; admins?: PersonViewSafe[];
postCreatorId?: number; postCreatorId?: number;
noBorder?: boolean; noBorder?: boolean;
noIndent?: boolean; noIndent?: boolean;

View file

@ -177,8 +177,10 @@ export class Community extends Component<any, State> {
let sort: SortType = pathSplit[6] let sort: SortType = pathSplit[6]
? SortType[pathSplit[6]] ? SortType[pathSplit[6]]
: UserService.Instance.user : UserService.Instance.localUserView
? Object.values(SortType)[UserService.Instance.user.default_sort_type] ? Object.values(SortType)[
UserService.Instance.localUserView.local_user.default_sort_type
]
: SortType.Active; : SortType.Active;
let page = pathSplit[8] ? Number(pathSplit[8]) : 1; let page = pathSplit[8] ? Number(pathSplit[8]) : 1;
@ -189,6 +191,7 @@ export class Community extends Component<any, State> {
limit: fetchLimit, limit: fetchLimit,
sort, sort,
type_: ListingType.Community, type_: ListingType.Community,
saved_only: false,
}; };
setOptionalAuth(getPostsForm, req.auth); setOptionalAuth(getPostsForm, req.auth);
this.setIdOrName(getPostsForm, id, name_); this.setIdOrName(getPostsForm, id, name_);
@ -199,6 +202,7 @@ export class Community extends Component<any, State> {
limit: fetchLimit, limit: fetchLimit,
sort, sort,
type_: ListingType.Community, type_: ListingType.Community,
saved_only: false,
}; };
setOptionalAuth(getCommentsForm, req.auth); setOptionalAuth(getCommentsForm, req.auth);
this.setIdOrName(getCommentsForm, id, name_); this.setIdOrName(getCommentsForm, id, name_);
@ -407,6 +411,7 @@ export class Community extends Component<any, State> {
type_: ListingType.Community, type_: ListingType.Community,
community_id: this.state.communityId, community_id: this.state.communityId,
community_name: this.state.communityName, community_name: this.state.communityName,
saved_only: false,
auth: authField(false), auth: authField(false),
}; };
WebSocketService.Instance.send(wsClient.getPosts(form)); WebSocketService.Instance.send(wsClient.getPosts(form));
@ -418,6 +423,7 @@ export class Community extends Component<any, State> {
type_: ListingType.Community, type_: ListingType.Community,
community_id: this.state.communityId, community_id: this.state.communityId,
community_name: this.state.communityName, community_name: this.state.communityName,
saved_only: false,
auth: authField(false), auth: authField(false),
}; };
WebSocketService.Instance.send(wsClient.getComments(form)); WebSocketService.Instance.send(wsClient.getComments(form));
@ -499,7 +505,7 @@ export class Community extends Component<any, State> {
// TODO this might be incorrect // TODO this might be incorrect
this.state.posts this.state.posts
.filter(p => p.creator.id == data.user_view.user.id) .filter(p => p.creator.id == data.person_view.person.id)
.forEach(p => (p.creator_banned_from_community = data.banned)); .forEach(p => (p.creator_banned_from_community = data.banned));
this.setState(this.state); this.setState(this.state);

View file

@ -28,7 +28,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
this.parseMessage = this.parseMessage.bind(this); this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
if (!UserService.Instance.user && isBrowser()) { if (!UserService.Instance.localUserView && isBrowser()) {
toast(i18n.t("not_logged_in"), "danger"); toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }

View file

@ -48,7 +48,7 @@ export class CreatePost extends Component<any, CreatePostState> {
this.handlePostCreate = this.handlePostCreate.bind(this); this.handlePostCreate = this.handlePostCreate.bind(this);
this.state = this.emptyState; this.state = this.emptyState;
if (!UserService.Instance.user && isBrowser()) { if (!UserService.Instance.localUserView && isBrowser()) {
toast(i18n.t("not_logged_in"), "danger"); toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }

View file

@ -7,10 +7,10 @@ import { UserService, WebSocketService } from "../services";
import { import {
SiteView, SiteView,
UserOperation, UserOperation,
GetUserDetailsResponse, GetPersonDetailsResponse,
UserViewSafe, PersonViewSafe,
SortType, SortType,
GetUserDetails, GetPersonDetails,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { import {
authField, authField,
@ -28,7 +28,7 @@ import { InitialFetchRequest } from "shared/interfaces";
interface CreatePrivateMessageState { interface CreatePrivateMessageState {
site_view: SiteView; site_view: SiteView;
recipient: UserViewSafe; recipient: PersonViewSafe;
recipient_id: number; recipient_id: number;
loading: boolean; loading: boolean;
} }
@ -55,7 +55,7 @@ export class CreatePrivateMessage extends Component<
this.parseMessage = this.parseMessage.bind(this); this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
if (!UserService.Instance.user) { if (!UserService.Instance.localUserView) {
toast(i18n.t("not_logged_in"), "danger"); toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }
@ -65,29 +65,29 @@ export class CreatePrivateMessage extends Component<
this.state.recipient = this.isoData.routeData[0].user; this.state.recipient = this.isoData.routeData[0].user;
this.state.loading = false; this.state.loading = false;
} else { } else {
this.fetchUserDetails(); this.fetchPersonDetails();
} }
} }
fetchUserDetails() { fetchPersonDetails() {
let form: GetUserDetails = { let form: GetPersonDetails = {
user_id: this.state.recipient_id, person_id: this.state.recipient_id,
sort: SortType.New, sort: SortType.New,
saved_only: false, saved_only: false,
auth: authField(false), auth: authField(false),
}; };
WebSocketService.Instance.send(wsClient.getUserDetails(form)); WebSocketService.Instance.send(wsClient.getPersonDetails(form));
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let user_id = Number(req.path.split("/").pop()); let person_id = Number(req.path.split("/").pop());
let form: GetUserDetails = { let form: GetPersonDetails = {
user_id, person_id,
sort: SortType.New, sort: SortType.New,
saved_only: false, saved_only: false,
auth: req.auth, auth: req.auth,
}; };
return [req.client.getUserDetails(form)]; return [req.client.getPersonDetails(form)];
} }
get documentTitle(): string { get documentTitle(): string {
@ -119,7 +119,7 @@ export class CreatePrivateMessage extends Component<
<h5>{i18n.t("create_private_message")}</h5> <h5>{i18n.t("create_private_message")}</h5>
<PrivateMessageForm <PrivateMessageForm
onCreate={this.handlePrivateMessageCreate} onCreate={this.handlePrivateMessageCreate}
recipient={this.state.recipient.user} recipient={this.state.recipient.person}
/> />
</div> </div>
</div> </div>
@ -142,9 +142,9 @@ export class CreatePrivateMessage extends Component<
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
return; return;
} else if (op == UserOperation.GetUserDetails) { } else if (op == UserOperation.GetPersonDetails) {
let data = wsJsonToRes<GetUserDetailsResponse>(msg).data; let data = wsJsonToRes<GetPersonDetailsResponse>(msg).data;
this.state.recipient = data.user_view; this.state.recipient = data.person_view;
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
} }

View file

@ -13,7 +13,9 @@ export class Icon extends Component<IconProps, any> {
render() { render() {
return ( return (
<svg class={`icon ${this.props.classes}`}> <svg class={`icon ${this.props.classes}`}>
<title>{this.props.icon}</title> <div class="sr-only">
<title>{this.props.icon}</title>
</div>
<use xlinkHref={`#icon-${this.props.icon}`}></use> <use xlinkHref={`#icon-${this.props.icon}`}></use>
</svg> </svg>
); );

View file

@ -65,7 +65,7 @@ export class ImageUploadForm extends Component<
accept="image/*,video/*" accept="image/*,video/*"
name={this.id} name={this.id}
class="d-none" class="d-none"
disabled={!UserService.Instance.user} disabled={!UserService.Instance.localUserView}
onChange={linkEvent(this, this.handleImageUpload)} onChange={linkEvent(this, this.handleImageUpload)}
/> />
</form> </form>

View file

@ -6,16 +6,16 @@ import {
SortType, SortType,
GetReplies, GetReplies,
GetRepliesResponse, GetRepliesResponse,
GetUserMentions, GetPersonMentions,
GetUserMentionsResponse, GetPersonMentionsResponse,
UserMentionResponse, PersonMentionResponse,
CommentResponse, CommentResponse,
PrivateMessageView, PrivateMessageView,
GetPrivateMessages, GetPrivateMessages,
PrivateMessagesResponse, PrivateMessagesResponse,
PrivateMessageResponse, PrivateMessageResponse,
SiteView, SiteView,
UserMentionView, PersonMentionView,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { WebSocketService, UserService } from "../services"; import { WebSocketService, UserService } from "../services";
import { import {
@ -62,7 +62,7 @@ enum ReplyEnum {
type ReplyType = { type ReplyType = {
id: number; id: number;
type_: ReplyEnum; type_: ReplyEnum;
view: CommentView | PrivateMessageView | UserMentionView; view: CommentView | PrivateMessageView | PersonMentionView;
published: string; published: string;
}; };
@ -70,7 +70,7 @@ interface InboxState {
unreadOrAll: UnreadOrAll; unreadOrAll: UnreadOrAll;
messageType: MessageType; messageType: MessageType;
replies: CommentView[]; replies: CommentView[];
mentions: UserMentionView[]; mentions: PersonMentionView[];
messages: PrivateMessageView[]; messages: PrivateMessageView[];
combined: ReplyType[]; combined: ReplyType[];
sort: SortType; sort: SortType;
@ -101,7 +101,7 @@ export class Inbox extends Component<any, InboxState> {
this.state = this.emptyState; this.state = this.emptyState;
this.handleSortChange = this.handleSortChange.bind(this); this.handleSortChange = this.handleSortChange.bind(this);
if (!UserService.Instance.user && isBrowser()) { if (!UserService.Instance.localUserView && isBrowser()) {
toast(i18n.t("not_logged_in"), "danger"); toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }
@ -128,9 +128,9 @@ export class Inbox extends Component<any, InboxState> {
} }
get documentTitle(): string { get documentTitle(): string {
return `@${UserService.Instance.user.name} ${i18n.t("inbox")} - ${ return `@${UserService.Instance.localUserView.person.name} ${i18n.t(
this.state.site_view.site.name "inbox"
}`; )} - ${this.state.site_view.site.name}`;
} }
render() { render() {
@ -307,9 +307,9 @@ export class Inbox extends Component<any, InboxState> {
}; };
} }
mentionToReplyType(r: UserMentionView): ReplyType { mentionToReplyType(r: PersonMentionView): ReplyType {
return { return {
id: r.user_mention.id, id: r.person_mention.id,
type_: ReplyEnum.Mention, type_: ReplyEnum.Mention,
view: r, view: r,
published: r.comment.published, published: r.comment.published,
@ -359,7 +359,7 @@ export class Inbox extends Component<any, InboxState> {
return ( return (
<CommentNodes <CommentNodes
key={i.id} key={i.id}
nodes={[{ comment_view: i.view as UserMentionView }]} nodes={[{ comment_view: i.view as PersonMentionView }]}
noIndent noIndent
markable markable
showCommunity showCommunity
@ -403,7 +403,7 @@ export class Inbox extends Component<any, InboxState> {
<div> <div>
{this.state.mentions.map(umv => ( {this.state.mentions.map(umv => (
<CommentNodes <CommentNodes
key={umv.user_mention.id} key={umv.person_mention.id}
nodes={[{ comment_view: umv }]} nodes={[{ comment_view: umv }]}
noIndent noIndent
markable markable
@ -491,14 +491,14 @@ export class Inbox extends Component<any, InboxState> {
}; };
promises.push(req.client.getReplies(repliesForm)); promises.push(req.client.getReplies(repliesForm));
let userMentionsForm: GetUserMentions = { let personMentionsForm: GetPersonMentions = {
sort: SortType.New, sort: SortType.New,
unread_only: true, unread_only: true,
page: 1, page: 1,
limit: fetchLimit, limit: fetchLimit,
auth: req.auth, auth: req.auth,
}; };
promises.push(req.client.getUserMentions(userMentionsForm)); promises.push(req.client.getPersonMentions(personMentionsForm));
let privateMessagesForm: GetPrivateMessages = { let privateMessagesForm: GetPrivateMessages = {
unread_only: true, unread_only: true,
@ -521,14 +521,16 @@ export class Inbox extends Component<any, InboxState> {
}; };
WebSocketService.Instance.send(wsClient.getReplies(repliesForm)); WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
let userMentionsForm: GetUserMentions = { let personMentionsForm: GetPersonMentions = {
sort: this.state.sort, sort: this.state.sort,
unread_only: this.state.unreadOrAll == UnreadOrAll.Unread, unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
page: this.state.page, page: this.state.page,
limit: fetchLimit, limit: fetchLimit,
auth: authField(), auth: authField(),
}; };
WebSocketService.Instance.send(wsClient.getUserMentions(userMentionsForm)); WebSocketService.Instance.send(
wsClient.getPersonMentions(personMentionsForm)
);
let privateMessagesForm: GetPrivateMessages = { let privateMessagesForm: GetPrivateMessages = {
unread_only: this.state.unreadOrAll == UnreadOrAll.Unread, unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
@ -579,8 +581,8 @@ export class Inbox extends Component<any, InboxState> {
window.scrollTo(0, 0); window.scrollTo(0, 0);
this.setState(this.state); this.setState(this.state);
setupTippy(); setupTippy();
} else if (op == UserOperation.GetUserMentions) { } else if (op == UserOperation.GetPersonMentions) {
let data = wsJsonToRes<GetUserMentionsResponse>(msg).data; let data = wsJsonToRes<GetPersonMentionsResponse>(msg).data;
this.state.mentions = data.mentions; this.state.mentions = data.mentions;
this.state.combined = this.buildCombined(); this.state.combined = this.buildCombined();
this.sendUnreadCount(); this.sendUnreadCount();
@ -698,48 +700,49 @@ export class Inbox extends Component<any, InboxState> {
this.sendUnreadCount(); this.sendUnreadCount();
this.setState(this.state); this.setState(this.state);
setupTippy(); setupTippy();
} else if (op == UserOperation.MarkUserMentionAsRead) { } else if (op == UserOperation.MarkPersonMentionAsRead) {
let data = wsJsonToRes<UserMentionResponse>(msg).data; let data = wsJsonToRes<PersonMentionResponse>(msg).data;
// TODO this might not be correct, it might need to use the comment id // TODO this might not be correct, it might need to use the comment id
let found = this.state.mentions.find( let found = this.state.mentions.find(
c => c.user_mention.id == data.user_mention_view.user_mention.id c => c.person_mention.id == data.person_mention_view.person_mention.id
); );
if (found) { if (found) {
let combinedView = this.state.combined.find( let combinedView = this.state.combined.find(
i => i.id == data.user_mention_view.user_mention.id i => i.id == data.person_mention_view.person_mention.id
).view as UserMentionView; ).view as PersonMentionView;
found.comment.content = combinedView.comment.content = found.comment.content = combinedView.comment.content =
data.user_mention_view.comment.content; data.person_mention_view.comment.content;
found.comment.updated = combinedView.comment.updated = found.comment.updated = combinedView.comment.updated =
data.user_mention_view.comment.updated; data.person_mention_view.comment.updated;
found.comment.removed = combinedView.comment.removed = found.comment.removed = combinedView.comment.removed =
data.user_mention_view.comment.removed; data.person_mention_view.comment.removed;
found.comment.deleted = combinedView.comment.deleted = found.comment.deleted = combinedView.comment.deleted =
data.user_mention_view.comment.deleted; data.person_mention_view.comment.deleted;
found.counts.upvotes = combinedView.counts.upvotes = found.counts.upvotes = combinedView.counts.upvotes =
data.user_mention_view.counts.upvotes; data.person_mention_view.counts.upvotes;
found.counts.downvotes = combinedView.counts.downvotes = found.counts.downvotes = combinedView.counts.downvotes =
data.user_mention_view.counts.downvotes; data.person_mention_view.counts.downvotes;
found.counts.score = combinedView.counts.score = found.counts.score = combinedView.counts.score =
data.user_mention_view.counts.score; data.person_mention_view.counts.score;
// If youre in the unread view, just remove it from the list // If youre in the unread view, just remove it from the list
if ( if (
this.state.unreadOrAll == UnreadOrAll.Unread && this.state.unreadOrAll == UnreadOrAll.Unread &&
data.user_mention_view.user_mention.read data.person_mention_view.person_mention.read
) { ) {
this.state.mentions = this.state.mentions.filter( this.state.mentions = this.state.mentions.filter(
r => r.user_mention.id !== data.user_mention_view.user_mention.id r =>
r.person_mention.id !== data.person_mention_view.person_mention.id
); );
this.state.combined = this.state.combined.filter( this.state.combined = this.state.combined.filter(
r => r.id !== data.user_mention_view.user_mention.id r => r.id !== data.person_mention_view.person_mention.id
); );
} else { } else {
// TODO test to make sure these mentions are getting marked as read // TODO test to make sure these mentions are getting marked as read
found.user_mention.read = combinedView.user_mention.read = found.person_mention.read = combinedView.person_mention.read =
data.user_mention_view.user_mention.read; data.person_mention_view.person_mention.read;
} }
} }
this.sendUnreadCount(); this.sendUnreadCount();
@ -747,18 +750,26 @@ export class Inbox extends Component<any, InboxState> {
} else if (op == UserOperation.CreateComment) { } else if (op == UserOperation.CreateComment) {
let data = wsJsonToRes<CommentResponse>(msg).data; let data = wsJsonToRes<CommentResponse>(msg).data;
if (data.recipient_ids.includes(UserService.Instance.user.id)) { if (
data.recipient_ids.includes(
UserService.Instance.localUserView.local_user.id
)
) {
this.state.replies.unshift(data.comment_view); this.state.replies.unshift(data.comment_view);
this.state.combined.unshift(this.replyToReplyType(data.comment_view)); this.state.combined.unshift(this.replyToReplyType(data.comment_view));
this.setState(this.state); this.setState(this.state);
} else if (data.comment_view.creator.id == UserService.Instance.user.id) { } else if (
data.comment_view.creator.id ==
UserService.Instance.localUserView.person.id
) {
// TODO this seems wrong, you should be using form_id // TODO this seems wrong, you should be using form_id
toast(i18n.t("reply_sent")); toast(i18n.t("reply_sent"));
} }
} else if (op == UserOperation.CreatePrivateMessage) { } else if (op == UserOperation.CreatePrivateMessage) {
let data = wsJsonToRes<PrivateMessageResponse>(msg).data; let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
if ( if (
data.private_message_view.recipient.id == UserService.Instance.user.id data.private_message_view.recipient.id ==
UserService.Instance.localUserView.person.id
) { ) {
this.state.messages.unshift(data.private_message_view); this.state.messages.unshift(data.private_message_view);
this.state.combined.unshift( this.state.combined.unshift(
@ -785,13 +796,13 @@ export class Inbox extends Component<any, InboxState> {
unreadCount(): number { unreadCount(): number {
return ( return (
this.state.replies.filter(r => !r.comment.read).length + this.state.replies.filter(r => !r.comment.read).length +
this.state.mentions.filter(r => !r.user_mention.read).length + this.state.mentions.filter(r => !r.person_mention.read).length +
this.state.messages.filter( this.state.messages.filter(
r => r =>
UserService.Instance.user && UserService.Instance.localUserView &&
!r.private_message.read && !r.private_message.read &&
// TODO also seems very strang and wrong // TODO also seems very strange and wrong
r.creator.id !== UserService.Instance.user.id r.creator.id !== UserService.Instance.localUserView.person.id
).length ).length
); );
} }

View file

@ -42,7 +42,11 @@ export class ListingTypeSelect extends Component<
<label <label
className={`btn btn-outline-secondary className={`btn btn-outline-secondary
${this.state.type_ == ListingType.Subscribed && "active"} ${this.state.type_ == ListingType.Subscribed && "active"}
${UserService.Instance.user == undefined ? "disabled" : "pointer"} ${
UserService.Instance.localUserView == undefined
? "disabled"
: "pointer"
}
`} `}
> >
<input <input
@ -51,7 +55,7 @@ export class ListingTypeSelect extends Component<
value={ListingType.Subscribed} value={ListingType.Subscribed}
checked={this.state.type_ == ListingType.Subscribed} checked={this.state.type_ == ListingType.Subscribed}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
disabled={UserService.Instance.user == undefined} disabled={UserService.Instance.localUserView == undefined}
/> />
{i18n.t("subscribed")} {i18n.t("subscribed")}
</label> </label>

View file

@ -21,7 +21,7 @@ import {
GetCommentsResponse, GetCommentsResponse,
CommentResponse, CommentResponse,
AddAdminResponse, AddAdminResponse,
BanUserResponse, BanPersonResponse,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { DataType, InitialFetchRequest } from "../interfaces"; import { DataType, InitialFetchRequest } from "../interfaces";
import { WebSocketService, UserService } from "../services"; import { WebSocketService, UserService } from "../services";
@ -31,7 +31,7 @@ import { SortSelect } from "./sort-select";
import { ListingTypeSelect } from "./listing-type-select"; import { ListingTypeSelect } from "./listing-type-select";
import { DataTypeSelect } from "./data-type-select"; import { DataTypeSelect } from "./data-type-select";
import { SiteForm } from "./site-form"; import { SiteForm } from "./site-form";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
import { BannerIconHeader } from "./banner-icon-header"; import { BannerIconHeader } from "./banner-icon-header";
import { Icon, Spinner } from "./icon"; import { Icon, Spinner } from "./icon";
@ -130,14 +130,14 @@ export class Main extends Component<any, MainState> {
this.state.comments = this.isoData.routeData[0].comments; this.state.comments = this.isoData.routeData[0].comments;
} }
this.state.trendingCommunities = this.isoData.routeData[1].communities; this.state.trendingCommunities = this.isoData.routeData[1].communities;
if (UserService.Instance.user) { if (UserService.Instance.localUserView) {
this.state.subscribedCommunities = this.isoData.routeData[2].communities; this.state.subscribedCommunities = this.isoData.routeData[2].communities;
} }
this.state.loading = false; this.state.loading = false;
} else { } else {
this.fetchTrendingCommunities(); this.fetchTrendingCommunities();
this.fetchData(); this.fetchData();
if (UserService.Instance.user) { if (UserService.Instance.localUserView) {
WebSocketService.Instance.send( WebSocketService.Instance.send(
wsClient.getFollowedCommunities({ wsClient.getFollowedCommunities({
auth: authField(), auth: authField(),
@ -194,15 +194,17 @@ export class Main extends Component<any, MainState> {
// TODO figure out auth default_listingType, default_sort_type // TODO figure out auth default_listingType, default_sort_type
let type_: ListingType = pathSplit[5] let type_: ListingType = pathSplit[5]
? ListingType[pathSplit[5]] ? ListingType[pathSplit[5]]
: UserService.Instance.user : UserService.Instance.localUserView
? Object.values(ListingType)[ ? Object.values(ListingType)[
UserService.Instance.user.default_listing_type UserService.Instance.localUserView.local_user.default_listing_type
] ]
: ListingType.Local; : ListingType.Local;
let sort: SortType = pathSplit[7] let sort: SortType = pathSplit[7]
? SortType[pathSplit[7]] ? SortType[pathSplit[7]]
: UserService.Instance.user : UserService.Instance.localUserView
? Object.values(SortType)[UserService.Instance.user.default_sort_type] ? Object.values(SortType)[
UserService.Instance.localUserView.local_user.default_sort_type
]
: SortType.Active; : SortType.Active;
let page = pathSplit[9] ? Number(pathSplit[9]) : 1; let page = pathSplit[9] ? Number(pathSplit[9]) : 1;
@ -215,6 +217,7 @@ export class Main extends Component<any, MainState> {
limit: fetchLimit, limit: fetchLimit,
sort, sort,
type_, type_,
saved_only: false,
}; };
setOptionalAuth(getPostsForm, req.auth); setOptionalAuth(getPostsForm, req.auth);
promises.push(req.client.getPosts(getPostsForm)); promises.push(req.client.getPosts(getPostsForm));
@ -224,6 +227,7 @@ export class Main extends Component<any, MainState> {
limit: fetchLimit, limit: fetchLimit,
sort, sort,
type_, type_,
saved_only: false,
}; };
setOptionalAuth(getCommentsForm, req.auth); setOptionalAuth(getCommentsForm, req.auth);
promises.push(req.client.getComments(getCommentsForm)); promises.push(req.client.getComments(getCommentsForm));
@ -294,7 +298,7 @@ export class Main extends Component<any, MainState> {
</div> </div>
</div> </div>
{UserService.Instance.user && {UserService.Instance.localUserView &&
this.state.subscribedCommunities.length > 0 && ( this.state.subscribedCommunities.length > 0 && (
<div class="card border-secondary mb-3"> <div class="card border-secondary mb-3">
<div class="card-body">{this.subscribedCommunities()}</div> <div class="card-body">{this.subscribedCommunities()}</div>
@ -413,7 +417,7 @@ export class Main extends Component<any, MainState> {
<li class="list-inline-item">{i18n.t("admins")}:</li> <li class="list-inline-item">{i18n.t("admins")}:</li>
{this.state.siteRes.admins.map(av => ( {this.state.siteRes.admins.map(av => (
<li class="list-inline-item"> <li class="list-inline-item">
<UserListing user={av.user} /> <PersonListing person={av.person} />
</li> </li>
))} ))}
</ul> </ul>
@ -609,7 +613,7 @@ export class Main extends Component<any, MainState> {
<Icon icon="rss" classes="text-muted small" /> <Icon icon="rss" classes="text-muted small" />
</a> </a>
)} )}
{UserService.Instance.user && {UserService.Instance.localUserView &&
this.state.listingType == ListingType.Subscribed && ( this.state.listingType == ListingType.Subscribed && (
<a <a
href={`/feeds/front/${UserService.Instance.auth}.xml?sort=${this.state.sort}`} href={`/feeds/front/${UserService.Instance.auth}.xml?sort=${this.state.sort}`}
@ -652,10 +656,10 @@ export class Main extends Component<any, MainState> {
get canAdmin(): boolean { get canAdmin(): boolean {
return ( return (
UserService.Instance.user && UserService.Instance.localUserView &&
this.state.siteRes.admins this.state.siteRes.admins
.map(a => a.user.id) .map(a => a.person.id)
.includes(UserService.Instance.user.id) .includes(UserService.Instance.localUserView.person.id)
); );
} }
@ -701,6 +705,7 @@ export class Main extends Component<any, MainState> {
limit: fetchLimit, limit: fetchLimit,
sort: this.state.sort, sort: this.state.sort,
type_: this.state.listingType, type_: this.state.listingType,
saved_only: false,
auth: authField(false), auth: authField(false),
}; };
WebSocketService.Instance.send(wsClient.getPosts(getPostsForm)); WebSocketService.Instance.send(wsClient.getPosts(getPostsForm));
@ -710,6 +715,7 @@ export class Main extends Component<any, MainState> {
limit: fetchLimit, limit: fetchLimit,
sort: this.state.sort, sort: this.state.sort,
type_: this.state.listingType, type_: this.state.listingType,
saved_only: false,
auth: authField(false), auth: authField(false),
}; };
WebSocketService.Instance.send(wsClient.getComments(getCommentsForm)); WebSocketService.Instance.send(wsClient.getComments(getCommentsForm));
@ -755,8 +761,8 @@ export class Main extends Component<any, MainState> {
let nsfwCheck = let nsfwCheck =
!nsfw || !nsfw ||
(nsfw && (nsfw &&
UserService.Instance.user && UserService.Instance.localUserView &&
UserService.Instance.user.show_nsfw); UserService.Instance.localUserView.local_user.show_nsfw);
// Only push these if you're on the first page, and you pass the nsfw check // Only push these if you're on the first page, and you pass the nsfw check
if (this.state.page == 1 && nsfwCheck) { if (this.state.page == 1 && nsfwCheck) {
@ -801,23 +807,23 @@ export class Main extends Component<any, MainState> {
let data = wsJsonToRes<AddAdminResponse>(msg).data; let data = wsJsonToRes<AddAdminResponse>(msg).data;
this.state.siteRes.admins = data.admins; this.state.siteRes.admins = data.admins;
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.BanUser) { } else if (op == UserOperation.BanPerson) {
let data = wsJsonToRes<BanUserResponse>(msg).data; let data = wsJsonToRes<BanPersonResponse>(msg).data;
let found = this.state.siteRes.banned.find( let found = this.state.siteRes.banned.find(
u => (u.user.id = data.user_view.user.id) p => (p.person.id = data.person_view.person.id)
); );
// Remove the banned if its found in the list, and the action is an unban // Remove the banned if its found in the list, and the action is an unban
if (found && !data.banned) { if (found && !data.banned) {
this.state.siteRes.banned = this.state.siteRes.banned.filter( this.state.siteRes.banned = this.state.siteRes.banned.filter(
i => i.user.id !== data.user_view.user.id i => i.person.id !== data.person_view.person.id
); );
} else { } else {
this.state.siteRes.banned.push(data.user_view); this.state.siteRes.banned.push(data.person_view);
} }
this.state.posts this.state.posts
.filter(p => p.creator.id == data.user_view.user.id) .filter(p => p.creator.id == data.person_view.person.id)
.forEach(p => (p.creator.banned = data.banned)); .forEach(p => (p.creator.banned = data.banned));
this.setState(this.state); this.setState(this.state);

View file

@ -206,7 +206,9 @@ export class MarkdownTextArea extends Component<
<form class="btn btn-sm text-muted font-weight-bold"> <form class="btn btn-sm text-muted font-weight-bold">
<label <label
htmlFor={`file-upload-${this.id}`} htmlFor={`file-upload-${this.id}`}
className={`mb-0 ${UserService.Instance.user && "pointer"}`} className={`mb-0 ${
UserService.Instance.localUserView && "pointer"
}`}
data-tippy-content={i18n.t("upload_image")} data-tippy-content={i18n.t("upload_image")}
> >
{this.state.imageLoading ? ( {this.state.imageLoading ? (
@ -221,7 +223,7 @@ export class MarkdownTextArea extends Component<
accept="image/*,video/*" accept="image/*,video/*"
name="file" name="file"
class="d-none" class="d-none"
disabled={!UserService.Instance.user} disabled={!UserService.Instance.localUserView}
onChange={linkEvent(this, this.handleImageUpload)} onChange={linkEvent(this, this.handleImageUpload)}
/> />
</form> </form>

View file

@ -32,7 +32,7 @@ import { HtmlTags } from "./html-tags";
import moment from "moment"; import moment from "moment";
import { i18n } from "../i18next"; import { i18n } from "../i18next";
import { InitialFetchRequest } from "shared/interfaces"; import { InitialFetchRequest } from "shared/interfaces";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
import { Spinner } from "./icon"; import { Spinner } from "./icon";
@ -252,7 +252,7 @@ export class Modlog extends Component<any, ModlogState> {
</span>, </span>,
<span> <span>
{" "} {" "}
by <UserListing user={mrc.commenter} /> by <PersonListing person={mrc.commenter} />
</span>, </span>,
mrc.mod_remove_comment.reason && mrc.mod_remove_comment.reason &&
` reason: ${mrc.mod_remove_comment.reason}`, ` reason: ${mrc.mod_remove_comment.reason}`,
@ -280,7 +280,7 @@ export class Modlog extends Component<any, ModlogState> {
{mbfc.mod_ban_from_community.banned ? "Banned " : "Unbanned "}{" "} {mbfc.mod_ban_from_community.banned ? "Banned " : "Unbanned "}{" "}
</span>, </span>,
<span> <span>
<UserListing user={mbfc.banned_user} /> <PersonListing person={mbfc.banned_person} />
</span>, </span>,
<span> from the community </span>, <span> from the community </span>,
<span> <span>
@ -305,7 +305,7 @@ export class Modlog extends Component<any, ModlogState> {
{mac.mod_add_community.removed ? "Removed " : "Appointed "}{" "} {mac.mod_add_community.removed ? "Removed " : "Appointed "}{" "}
</span>, </span>,
<span> <span>
<UserListing user={mac.modded_user} /> <PersonListing person={mac.modded_person} />
</span>, </span>,
<span> as a mod to the community </span>, <span> as a mod to the community </span>,
<span> <span>
@ -318,7 +318,7 @@ export class Modlog extends Component<any, ModlogState> {
return [ return [
<span>{mb.mod_ban.banned ? "Banned " : "Unbanned "} </span>, <span>{mb.mod_ban.banned ? "Banned " : "Unbanned "} </span>,
<span> <span>
<UserListing user={mb.banned_user} /> <PersonListing person={mb.banned_person} />
</span>, </span>,
<div>{mb.mod_ban.reason && ` reason: ${mb.mod_ban.reason}`}</div>, <div>{mb.mod_ban.reason && ` reason: ${mb.mod_ban.reason}`}</div>,
<div> <div>
@ -332,7 +332,7 @@ export class Modlog extends Component<any, ModlogState> {
return [ return [
<span>{ma.mod_add.removed ? "Removed " : "Appointed "} </span>, <span>{ma.mod_add.removed ? "Removed " : "Appointed "} </span>,
<span> <span>
<UserListing user={ma.modded_user} /> <PersonListing person={ma.modded_person} />
</span>, </span>,
<span> as an admin </span>, <span> as an admin </span>,
]; ];
@ -353,7 +353,7 @@ export class Modlog extends Component<any, ModlogState> {
<MomentTime data={i} /> <MomentTime data={i} />
</td> </td>
<td> <td>
<UserListing user={i.view.moderator} /> <PersonListing person={i.view.moderator} />
</td> </td>
<td>{this.renderModlogType(i)}</td> <td>{this.renderModlogType(i)}</td>
</tr> </tr>

View file

@ -6,8 +6,8 @@ import {
UserOperation, UserOperation,
GetReplies, GetReplies,
GetRepliesResponse, GetRepliesResponse,
GetUserMentions, GetPersonMentions,
GetUserMentionsResponse, GetPersonMentionsResponse,
GetPrivateMessages, GetPrivateMessages,
PrivateMessagesResponse, PrivateMessagesResponse,
SortType, SortType,
@ -174,7 +174,8 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
// TODO class active corresponding to current page // TODO class active corresponding to current page
navbar() { navbar() {
let user = UserService.Instance.user || this.props.site_res.my_user; let localUserView =
UserService.Instance.localUserView || this.props.site_res.my_user;
return ( return (
<nav class="navbar navbar-expand-lg navbar-light shadow-sm p-0 px-3"> <nav class="navbar navbar-expand-lg navbar-light shadow-sm p-0 px-3">
<div class="container"> <div class="container">
@ -261,7 +262,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
title={i18n.t("support_lemmy")} title={i18n.t("support_lemmy")}
href={supportLemmyUrl} href={supportLemmyUrl}
> >
<Icon icon="beer" classes="small" /> <Icon icon="heart" classes="small" />
</a> </a>
</li> </li>
</ul> </ul>
@ -338,16 +339,16 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
<li className="nav-item"> <li className="nav-item">
<Link <Link
className="nav-link" className="nav-link"
to={`/u/${user.name}`} to={`/u/${localUserView.person.name}`}
title={i18n.t("settings")} title={i18n.t("settings")}
> >
<span> <span>
{user.avatar && showAvatars() && ( {localUserView.person.avatar && showAvatars() && (
<PictrsImage src={user.avatar} icon /> <PictrsImage src={localUserView.person.avatar} icon />
)} )}
{user.preferred_username {localUserView.person.preferred_username
? user.preferred_username ? localUserView.person.preferred_username
: user.name} : localUserView.person.name}
</span> </span>
</Link> </Link>
</li> </li>
@ -400,8 +401,8 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
this.state.unreadCount = this.calculateUnreadCount(); this.state.unreadCount = this.calculateUnreadCount();
this.setState(this.state); this.setState(this.state);
this.sendUnreadCount(); this.sendUnreadCount();
} else if (op == UserOperation.GetUserMentions) { } else if (op == UserOperation.GetPersonMentions) {
let data = wsJsonToRes<GetUserMentionsResponse>(msg).data; let data = wsJsonToRes<GetPersonMentionsResponse>(msg).data;
let unreadMentions = data.mentions.filter(r => !r.comment.read); let unreadMentions = data.mentions.filter(r => !r.comment.read);
this.state.mentions = unreadMentions; this.state.mentions = unreadMentions;
@ -422,8 +423,8 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
// This is only called on a successful login // This is only called on a successful login
let data = wsJsonToRes<GetSiteResponse>(msg).data; let data = wsJsonToRes<GetSiteResponse>(msg).data;
console.log(data.my_user); console.log(data.my_user);
UserService.Instance.user = data.my_user; UserService.Instance.localUserView = data.my_user;
setTheme(UserService.Instance.user.theme); setTheme(UserService.Instance.localUserView.local_user.theme);
i18n.changeLanguage(getLanguage()); i18n.changeLanguage(getLanguage());
this.state.isLoggedIn = true; this.state.isLoggedIn = true;
this.setState(this.state); this.setState(this.state);
@ -431,7 +432,11 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
let data = wsJsonToRes<CommentResponse>(msg).data; let data = wsJsonToRes<CommentResponse>(msg).data;
if (this.state.isLoggedIn) { if (this.state.isLoggedIn) {
if (data.recipient_ids.includes(UserService.Instance.user.id)) { if (
data.recipient_ids.includes(
UserService.Instance.localUserView.local_user.id
)
) {
this.state.replies.push(data.comment_view); this.state.replies.push(data.comment_view);
this.state.unreadCount++; this.state.unreadCount++;
this.setState(this.state); this.setState(this.state);
@ -444,7 +449,8 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
if (this.state.isLoggedIn) { if (this.state.isLoggedIn) {
if ( if (
data.private_message_view.recipient.id == UserService.Instance.user.id data.private_message_view.recipient.id ==
UserService.Instance.localUserView.person.id
) { ) {
this.state.messages.push(data.private_message_view); this.state.messages.push(data.private_message_view);
this.state.unreadCount++; this.state.unreadCount++;
@ -466,7 +472,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
auth: authField(), auth: authField(),
}; };
let userMentionsForm: GetUserMentions = { let personMentionsForm: GetPersonMentions = {
sort: SortType.New, sort: SortType.New,
unread_only: true, unread_only: true,
page: 1, page: 1,
@ -484,7 +490,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
if (this.currentLocation !== "/inbox") { if (this.currentLocation !== "/inbox") {
WebSocketService.Instance.send(wsClient.getReplies(repliesForm)); WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
WebSocketService.Instance.send( WebSocketService.Instance.send(
wsClient.getUserMentions(userMentionsForm) wsClient.getPersonMentions(personMentionsForm)
); );
WebSocketService.Instance.send( WebSocketService.Instance.send(
wsClient.getPrivateMessages(privateMessagesForm) wsClient.getPrivateMessages(privateMessagesForm)
@ -510,15 +516,15 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
get canAdmin(): boolean { get canAdmin(): boolean {
return ( return (
UserService.Instance.user && UserService.Instance.localUserView &&
this.props.site_res.admins this.props.site_res.admins
.map(a => a.user.id) .map(a => a.person.id)
.includes(UserService.Instance.user.id) .includes(UserService.Instance.localUserView.person.id)
); );
} }
requestNotificationPermission() { requestNotificationPermission() {
if (UserService.Instance.user) { if (UserService.Instance.localUserView) {
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
if (!Notification) { if (!Notification) {
toast(i18n.t("notifications_error"), "danger"); toast(i18n.t("notifications_error"), "danger");

View file

@ -4,23 +4,23 @@ import {
PostView, PostView,
CommentView, CommentView,
SortType, SortType,
GetUserDetailsResponse, GetPersonDetailsResponse,
UserViewSafe, PersonViewSafe,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { UserDetailsView } from "../interfaces"; import { PersonDetailsView } from "../interfaces";
import { commentsToFlatNodes, setupTippy } from "../utils"; import { commentsToFlatNodes, setupTippy } from "../utils";
import { PostListing } from "./post-listing"; import { PostListing } from "./post-listing";
import { CommentNodes } from "./comment-nodes"; import { CommentNodes } from "./comment-nodes";
interface UserDetailsProps { interface PersonDetailsProps {
userRes: GetUserDetailsResponse; personRes: GetPersonDetailsResponse;
admins: UserViewSafe[]; admins: PersonViewSafe[];
page: number; page: number;
limit: number; limit: number;
sort: SortType; sort: SortType;
enableDownvotes: boolean; enableDownvotes: boolean;
enableNsfw: boolean; enableNsfw: boolean;
view: UserDetailsView; view: PersonDetailsView;
onPageChange(page: number): number | any; onPageChange(page: number): number | any;
} }
@ -36,7 +36,7 @@ type ItemType = {
score: number; score: number;
}; };
export class UserDetails extends Component<UserDetailsProps, any> { export class PersonDetails extends Component<PersonDetailsProps, any> {
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
} }
@ -65,12 +65,15 @@ export class UserDetails extends Component<UserDetailsProps, any> {
); );
} }
viewSelector(view: UserDetailsView) { viewSelector(view: PersonDetailsView) {
if (view === UserDetailsView.Overview || view === UserDetailsView.Saved) { if (
view === PersonDetailsView.Overview ||
view === PersonDetailsView.Saved
) {
return this.overview(); return this.overview();
} else if (view === UserDetailsView.Comments) { } else if (view === PersonDetailsView.Comments) {
return this.comments(); return this.comments();
} else if (view === UserDetailsView.Posts) { } else if (view === PersonDetailsView.Posts) {
return this.posts(); return this.posts();
} else { } else {
return null; return null;
@ -114,14 +117,14 @@ export class UserDetails extends Component<UserDetailsProps, any> {
overview() { overview() {
let id = 0; let id = 0;
let comments: ItemType[] = this.props.userRes.comments.map(r => ({ let comments: ItemType[] = this.props.personRes.comments.map(r => ({
id: id++, id: id++,
type_: ItemEnum.Comment, type_: ItemEnum.Comment,
view: r, view: r,
published: r.comment.published, published: r.comment.published,
score: r.counts.score, score: r.counts.score,
})); }));
let posts: ItemType[] = this.props.userRes.posts.map(r => ({ let posts: ItemType[] = this.props.personRes.posts.map(r => ({
id: id++, id: id++,
type_: ItemEnum.Post, type_: ItemEnum.Post,
view: r, view: r,
@ -149,7 +152,7 @@ export class UserDetails extends Component<UserDetailsProps, any> {
return ( return (
<div> <div>
<CommentNodes <CommentNodes
nodes={commentsToFlatNodes(this.props.userRes.comments)} nodes={commentsToFlatNodes(this.props.personRes.comments)}
admins={this.props.admins} admins={this.props.admins}
noIndent noIndent
showCommunity showCommunity
@ -163,7 +166,7 @@ export class UserDetails extends Component<UserDetailsProps, any> {
posts() { posts() {
return ( return (
<div> <div>
{this.props.userRes.posts.map(post => ( {this.props.personRes.posts.map(post => (
<> <>
<PostListing <PostListing
post_view={post} post_view={post}
@ -190,7 +193,8 @@ export class UserDetails extends Component<UserDetailsProps, any> {
{i18n.t("prev")} {i18n.t("prev")}
</button> </button>
)} )}
{this.props.userRes.comments.length + this.props.userRes.posts.length > {this.props.personRes.comments.length +
this.props.personRes.posts.length >
0 && ( 0 && (
<button <button
class="btn btn-secondary" class="btn btn-secondary"
@ -203,11 +207,11 @@ export class UserDetails extends Component<UserDetailsProps, any> {
); );
} }
nextPage(i: UserDetails) { nextPage(i: PersonDetails) {
i.props.onPageChange(i.props.page + 1); i.props.onPageChange(i.props.page + 1);
} }
prevPage(i: UserDetails) { prevPage(i: PersonDetails) {
i.props.onPageChange(i.props.page - 1); i.props.onPageChange(i.props.page - 1);
} }
} }

View file

@ -1,12 +1,12 @@
import { Component } from "inferno"; import { Component } from "inferno";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { UserSafe } from "lemmy-js-client"; import { PersonSafe } from "lemmy-js-client";
import { showAvatars, hostname, isCakeDay } from "../utils"; import { showAvatars, hostname, isCakeDay } from "../utils";
import { CakeDay } from "./cake-day"; import { CakeDay } from "./cake-day";
import { PictrsImage } from "./pictrs-image"; import { PictrsImage } from "./pictrs-image";
interface UserListingProps { interface PersonListingProps {
user: UserSafe; person: PersonSafe;
realLink?: boolean; realLink?: boolean;
useApubName?: boolean; useApubName?: boolean;
muted?: boolean; muted?: boolean;
@ -14,31 +14,31 @@ interface UserListingProps {
showApubName?: boolean; showApubName?: boolean;
} }
export class UserListing extends Component<UserListingProps, any> { export class PersonListing extends Component<PersonListingProps, any> {
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
} }
render() { render() {
let user = this.props.user; let person = this.props.person;
let local = user.local == null ? true : user.local; let local = person.local == null ? true : person.local;
let apubName: string, link: string; let apubName: string, link: string;
if (local) { if (local) {
apubName = `@${user.name}`; apubName = `@${person.name}`;
link = `/u/${user.name}`; link = `/u/${person.name}`;
} else { } else {
apubName = `@${user.name}@${hostname(user.actor_id)}`; apubName = `@${person.name}@${hostname(person.actor_id)}`;
link = !this.props.realLink ? `/user/${user.id}` : user.actor_id; link = !this.props.realLink ? `/user/${person.id}` : person.actor_id;
} }
let displayName = this.props.useApubName let displayName = this.props.useApubName
? apubName ? apubName
: user.preferred_username : person.preferred_username
? user.preferred_username ? person.preferred_username
: apubName; : apubName;
if (this.props.showApubName && !local && user.preferred_username) { if (this.props.showApubName && !local && person.preferred_username) {
displayName = `${displayName} (${apubName})`; displayName = `${displayName} (${apubName})`;
} }
@ -49,13 +49,13 @@ export class UserListing extends Component<UserListingProps, any> {
className={this.props.muted ? "text-muted" : "text-info"} className={this.props.muted ? "text-muted" : "text-info"}
to={link} to={link}
> >
{!this.props.hideAvatar && user.avatar && showAvatars() && ( {!this.props.hideAvatar && person.avatar && showAvatars() && (
<PictrsImage src={user.avatar} icon /> <PictrsImage src={person.avatar} icon />
)} )}
<span>{displayName}</span> <span>{displayName}</span>
</Link> </Link>
{isCakeDay(user.published) && <CakeDay creatorName={apubName} />} {isCakeDay(person.published) && <CakeDay creatorName={apubName} />}
</> </>
); );
} }

View file

@ -1,6 +1,7 @@
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { Subscription } from "rxjs"; import { Subscription } from "rxjs";
import ISO6391 from "iso-639-1";
import { import {
UserOperation, UserOperation,
SortType, SortType,
@ -9,14 +10,14 @@ import {
LoginResponse, LoginResponse,
DeleteAccount, DeleteAccount,
GetSiteResponse, GetSiteResponse,
GetUserDetailsResponse, GetPersonDetailsResponse,
AddAdminResponse, AddAdminResponse,
GetUserDetails, GetPersonDetails,
CommentResponse, CommentResponse,
PostResponse, PostResponse,
BanUserResponse, BanPersonResponse,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { InitialFetchRequest, UserDetailsView } from "../interfaces"; import { InitialFetchRequest, PersonDetailsView } from "../interfaces";
import { WebSocketService, UserService } from "../services"; import { WebSocketService, UserService } from "../services";
import { import {
wsJsonToRes, wsJsonToRes,
@ -48,25 +49,25 @@ import {
saveScrollPosition, saveScrollPosition,
restoreScrollPosition, restoreScrollPosition,
} from "../utils"; } from "../utils";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { HtmlTags } from "./html-tags"; import { HtmlTags } from "./html-tags";
import { SortSelect } from "./sort-select"; import { SortSelect } from "./sort-select";
import { ListingTypeSelect } from "./listing-type-select"; import { ListingTypeSelect } from "./listing-type-select";
import { MomentTime } from "./moment-time"; import { MomentTime } from "./moment-time";
import { i18n } from "../i18next"; import { i18n } from "../i18next";
import moment from "moment"; import moment from "moment";
import { UserDetails } from "./user-details"; import { PersonDetails } from "./person-details";
import { MarkdownTextArea } from "./markdown-textarea"; import { MarkdownTextArea } from "./markdown-textarea";
import { Icon, Spinner } from "./icon"; import { Icon, Spinner } from "./icon";
import { ImageUploadForm } from "./image-upload-form"; import { ImageUploadForm } from "./image-upload-form";
import { BannerIconHeader } from "./banner-icon-header"; import { BannerIconHeader } from "./banner-icon-header";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
interface UserState { interface PersonState {
userRes: GetUserDetailsResponse; personRes: GetPersonDetailsResponse;
userId: number; personId: number;
userName: string; userName: string;
view: UserDetailsView; view: PersonDetailsView;
sort: SortType; sort: SortType;
page: number; page: number;
loading: boolean; loading: boolean;
@ -78,11 +79,11 @@ interface UserState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
} }
interface UserProps { interface PersonProps {
view: UserDetailsView; view: PersonDetailsView;
sort: SortType; sort: SortType;
page: number; page: number;
user_id: number | null; person_id: number | null;
username: string; username: string;
} }
@ -92,17 +93,17 @@ interface UrlParams {
page?: number; page?: number;
} }
export class User extends Component<any, UserState> { export class Person extends Component<any, PersonState> {
private isoData = setIsoData(this.context); private isoData = setIsoData(this.context);
private subscription: Subscription; private subscription: Subscription;
private emptyState: UserState = { private emptyState: PersonState = {
userRes: undefined, personRes: undefined,
userId: getIdFromProps(this.props), personId: getIdFromProps(this.props),
userName: getUsernameFromProps(this.props), userName: getUsernameFromProps(this.props),
loading: true, loading: true,
view: User.getViewFromProps(this.props.match.view), view: Person.getViewFromProps(this.props.match.view),
sort: User.getSortTypeFromProps(this.props.match.sort), sort: Person.getSortTypeFromProps(this.props.match.sort),
page: User.getPageFromProps(this.props.match.page), page: Person.getPageFromProps(this.props.match.page),
userSettingsForm: { userSettingsForm: {
show_nsfw: null, show_nsfw: null,
theme: null, theme: null,
@ -152,7 +153,7 @@ export class User extends Component<any, UserState> {
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path == this.context.router.route.match.url) {
this.state.userRes = this.isoData.routeData[0]; this.state.personRes = this.isoData.routeData[0];
this.setUserInfo(); this.setUserInfo();
this.state.loading = false; this.state.loading = false;
} else { } else {
@ -163,27 +164,27 @@ export class User extends Component<any, UserState> {
} }
fetchUserData() { fetchUserData() {
let form: GetUserDetails = { let form: GetPersonDetails = {
user_id: this.state.userId, person_id: this.state.personId,
username: this.state.userName, username: this.state.userName,
sort: this.state.sort, sort: this.state.sort,
saved_only: this.state.view === UserDetailsView.Saved, saved_only: this.state.view === PersonDetailsView.Saved,
page: this.state.page, page: this.state.page,
limit: fetchLimit, limit: fetchLimit,
auth: authField(false), auth: authField(false),
}; };
WebSocketService.Instance.send(wsClient.getUserDetails(form)); WebSocketService.Instance.send(wsClient.getPersonDetails(form));
} }
get isCurrentUser() { get isCurrentUser() {
return ( return (
UserService.Instance.user && UserService.Instance.localUserView?.person.id ==
UserService.Instance.user.id == this.state.userRes.user_view.user.id this.state.personRes.person_view.person.id
); );
} }
static getViewFromProps(view: string): UserDetailsView { static getViewFromProps(view: string): PersonDetailsView {
return view ? UserDetailsView[view] : UserDetailsView.Overview; return view ? PersonDetailsView[view] : PersonDetailsView.Overview;
} }
static getSortTypeFromProps(sort: string): SortType { static getSortTypeFromProps(sort: string): SortType {
@ -200,33 +201,33 @@ export class User extends Component<any, UserState> {
// It can be /u/me, or /username/1 // It can be /u/me, or /username/1
let idOrName = pathSplit[2]; let idOrName = pathSplit[2];
let user_id: number; let person_id: number;
let username: string; let username: string;
if (isNaN(Number(idOrName))) { if (isNaN(Number(idOrName))) {
username = idOrName; username = idOrName;
} else { } else {
user_id = Number(idOrName); person_id = Number(idOrName);
} }
let view = this.getViewFromProps(pathSplit[4]); let view = this.getViewFromProps(pathSplit[4]);
let sort = this.getSortTypeFromProps(pathSplit[6]); let sort = this.getSortTypeFromProps(pathSplit[6]);
let page = this.getPageFromProps(Number(pathSplit[8])); let page = this.getPageFromProps(Number(pathSplit[8]));
let form: GetUserDetails = { let form: GetPersonDetails = {
sort, sort,
saved_only: view === UserDetailsView.Saved, saved_only: view === PersonDetailsView.Saved,
page, page,
limit: fetchLimit, limit: fetchLimit,
}; };
setOptionalAuth(form, req.auth); setOptionalAuth(form, req.auth);
this.setIdOrName(form, user_id, username); this.setIdOrName(form, person_id, username);
promises.push(req.client.getUserDetails(form)); promises.push(req.client.getPersonDetails(form));
return promises; return promises;
} }
static setIdOrName(obj: any, id: number, name_: string) { static setIdOrName(obj: any, id: number, name_: string) {
if (id) { if (id) {
obj.user_id = id; obj.person_id = id;
} else { } else {
obj.username = name_; obj.username = name_;
} }
@ -237,12 +238,12 @@ export class User extends Component<any, UserState> {
saveScrollPosition(this.context); saveScrollPosition(this.context);
} }
static getDerivedStateFromProps(props: any): UserProps { static getDerivedStateFromProps(props: any): PersonProps {
return { return {
view: this.getViewFromProps(props.match.params.view), view: this.getViewFromProps(props.match.params.view),
sort: this.getSortTypeFromProps(props.match.params.sort), sort: this.getSortTypeFromProps(props.match.params.sort),
page: this.getPageFromProps(props.match.params.page), page: this.getPageFromProps(props.match.params.page),
user_id: Number(props.match.params.id) || null, person_id: Number(props.match.params.id) || null,
username: props.match.params.username, username: props.match.params.username,
}; };
} }
@ -259,12 +260,12 @@ export class User extends Component<any, UserState> {
} }
get documentTitle(): string { get documentTitle(): string {
return `@${this.state.userRes.user_view.user.name} - ${this.state.siteRes.site_view.site.name}`; return `@${this.state.personRes.person_view.person.name} - ${this.state.siteRes.site_view.site.name}`;
} }
get bioTag(): string { get bioTag(): string {
return this.state.userRes.user_view.user.bio return this.state.personRes.person_view.person.bio
? previewLines(this.state.userRes.user_view.user.bio) ? previewLines(this.state.personRes.person_view.person.bio)
: undefined; : undefined;
} }
@ -283,14 +284,14 @@ export class User extends Component<any, UserState> {
title={this.documentTitle} title={this.documentTitle}
path={this.context.router.route.match.url} path={this.context.router.route.match.url}
description={this.bioTag} description={this.bioTag}
image={this.state.userRes.user_view.user.avatar} image={this.state.personRes.person_view.person.avatar}
/> />
{this.userInfo()} {this.userInfo()}
<hr /> <hr />
</> </>
{!this.state.loading && this.selects()} {!this.state.loading && this.selects()}
<UserDetails <PersonDetails
userRes={this.state.userRes} personRes={this.state.personRes}
admins={this.state.siteRes.admins} admins={this.state.siteRes.admins}
sort={this.state.sort} sort={this.state.sort}
page={this.state.page} page={this.state.page}
@ -322,52 +323,52 @@ export class User extends Component<any, UserState> {
<div class="btn-group btn-group-toggle flex-wrap mb-2"> <div class="btn-group btn-group-toggle flex-wrap mb-2">
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.view == UserDetailsView.Overview && "active"} ${this.state.view == PersonDetailsView.Overview && "active"}
`} `}
> >
<input <input
type="radio" type="radio"
value={UserDetailsView.Overview} value={PersonDetailsView.Overview}
checked={this.state.view === UserDetailsView.Overview} checked={this.state.view === PersonDetailsView.Overview}
onChange={linkEvent(this, this.handleViewChange)} onChange={linkEvent(this, this.handleViewChange)}
/> />
{i18n.t("overview")} {i18n.t("overview")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.view == UserDetailsView.Comments && "active"} ${this.state.view == PersonDetailsView.Comments && "active"}
`} `}
> >
<input <input
type="radio" type="radio"
value={UserDetailsView.Comments} value={PersonDetailsView.Comments}
checked={this.state.view == UserDetailsView.Comments} checked={this.state.view == PersonDetailsView.Comments}
onChange={linkEvent(this, this.handleViewChange)} onChange={linkEvent(this, this.handleViewChange)}
/> />
{i18n.t("comments")} {i18n.t("comments")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.view == UserDetailsView.Posts && "active"} ${this.state.view == PersonDetailsView.Posts && "active"}
`} `}
> >
<input <input
type="radio" type="radio"
value={UserDetailsView.Posts} value={PersonDetailsView.Posts}
checked={this.state.view == UserDetailsView.Posts} checked={this.state.view == PersonDetailsView.Posts}
onChange={linkEvent(this, this.handleViewChange)} onChange={linkEvent(this, this.handleViewChange)}
/> />
{i18n.t("posts")} {i18n.t("posts")}
</label> </label>
<label <label
className={`btn btn-outline-secondary pointer className={`btn btn-outline-secondary pointer
${this.state.view == UserDetailsView.Saved && "active"} ${this.state.view == PersonDetailsView.Saved && "active"}
`} `}
> >
<input <input
type="radio" type="radio"
value={UserDetailsView.Saved} value={PersonDetailsView.Saved}
checked={this.state.view == UserDetailsView.Saved} checked={this.state.view == PersonDetailsView.Saved}
onChange={linkEvent(this, this.handleViewChange)} onChange={linkEvent(this, this.handleViewChange)}
/> />
{i18n.t("saved")} {i18n.t("saved")}
@ -398,29 +399,29 @@ export class User extends Component<any, UserState> {
} }
userInfo() { userInfo() {
let uv = this.state.userRes?.user_view; let pv = this.state.personRes?.person_view;
return ( return (
<div> <div>
<BannerIconHeader banner={uv.user.banner} icon={uv.user.avatar} /> <BannerIconHeader banner={pv.person.banner} icon={pv.person.avatar} />
<div class="mb-3"> <div class="mb-3">
<div class=""> <div class="">
<div class="mb-0 d-flex flex-wrap"> <div class="mb-0 d-flex flex-wrap">
<div> <div>
{uv.user.preferred_username && ( {pv.person.preferred_username && (
<h5 class="mb-0">{uv.user.preferred_username}</h5> <h5 class="mb-0">{pv.person.preferred_username}</h5>
)} )}
<ul class="list-inline mb-2"> <ul class="list-inline mb-2">
<li className="list-inline-item"> <li className="list-inline-item">
<UserListing <PersonListing
user={uv.user} person={pv.person}
realLink realLink
useApubName useApubName
muted muted
hideAvatar hideAvatar
/> />
</li> </li>
{uv.user.banned && ( {pv.person.banned && (
<li className="list-inline-item badge badge-danger"> <li className="list-inline-item badge badge-danger">
{i18n.t("banned")} {i18n.t("banned")}
</li> </li>
@ -437,53 +438,56 @@ export class User extends Component<any, UserState> {
</button> </button>
) : ( ) : (
<> <>
{/* TODO matrix ids aren't currently federated, so don't come back with GetPersonDetails
<a <a
className={`d-flex align-self-start btn btn-secondary mr-2 ${ className={`d-flex align-self-start btn btn-secondary mr-2 ${
!uv.user.matrix_user_id && "invisible" !pv.local_user.matrix_user_id && "invisible"
}`} }`}
rel="noopener" rel="noopener"
href={`https://matrix.to/#/${uv.user.matrix_user_id}`} href={`https://matrix.to/#/${pv.local_user.matrix_user_id}`}
> >
{i18n.t("send_secure_message")} {i18n.t("send_secure_message")}
</a> </a>
*/}
<Link <Link
className={"d-flex align-self-start btn btn-secondary"} className={"d-flex align-self-start btn btn-secondary"}
to={`/create_private_message/recipient/${uv.user.id}`} to={`/create_private_message/recipient/${pv.person.id}`}
> >
{i18n.t("send_message")} {i18n.t("send_message")}
</Link> </Link>
</> </>
)} )}
</div> </div>
{uv.user.bio && ( {pv.person.bio && (
<div className="d-flex align-items-center mb-2"> <div className="d-flex align-items-center mb-2">
<div <div
className="md-div" className="md-div"
dangerouslySetInnerHTML={mdToHtml(uv.user.bio)} dangerouslySetInnerHTML={mdToHtml(pv.person.bio)}
/> />
</div> </div>
)} )}
<div> <div>
<ul class="list-inline mb-2"> <ul class="list-inline mb-2">
<li className="list-inline-item badge badge-light"> <li className="list-inline-item badge badge-light">
{i18n.t("number_of_posts", { count: uv.counts.post_count })} {i18n.t("number_of_posts", { count: pv.counts.post_count })}
</li> </li>
<li className="list-inline-item badge badge-light"> <li className="list-inline-item badge badge-light">
{i18n.t("number_of_comments", { {i18n.t("number_of_comments", {
count: uv.counts.comment_count, count: pv.counts.comment_count,
})} })}
</li> </li>
</ul> </ul>
</div> </div>
<div class="text-muted"> <div class="text-muted">
{i18n.t("joined")}{" "} {i18n.t("joined")}{" "}
<MomentTime data={uv.user} showAgo ignoreUpdated /> <MomentTime data={pv.person} showAgo ignoreUpdated />
</div> </div>
<div className="d-flex align-items-center text-muted mb-2"> <div className="d-flex align-items-center text-muted mb-2">
<Icon icon="cake" /> <Icon icon="cake" />
<span className="ml-2"> <span className="ml-2">
{i18n.t("cake_day_title")}{" "} {i18n.t("cake_day_title")}{" "}
{moment.utc(uv.user.published).local().format("MMM DD, YYYY")} {moment.utc(pv.person.published).local().format("MMM DD, YYYY")}
</span> </span>
</div> </div>
</div> </div>
@ -533,8 +537,10 @@ export class User extends Component<any, UserState> {
<option disabled aria-hidden="true"> <option disabled aria-hidden="true">
</option> </option>
{languages.map(lang => ( {languages.sort().map(lang => (
<option value={lang.code}>{lang.name}</option> <option value={lang.code}>
{ISO6391.getNativeName(lang.code) || lang.code}
</option>
))} ))}
</select> </select>
</div> </div>
@ -557,7 +563,7 @@ export class User extends Component<any, UserState> {
</div> </div>
<form className="form-group"> <form className="form-group">
<label> <label>
<div class="mr-2">{i18n.t("sort_type")}</div> <div class="mr-2">{i18n.t("type")}</div>
</label> </label>
<ListingTypeSelect <ListingTypeSelect
type_={ type_={
@ -573,7 +579,7 @@ export class User extends Component<any, UserState> {
</form> </form>
<form className="form-group"> <form className="form-group">
<label> <label>
<div class="mr-2">{i18n.t("type")}</div> <div class="mr-2">{i18n.t("sort_type")}</div>
</label> </label>
<SortSelect <SortSelect
sort={ sort={
@ -845,12 +851,12 @@ export class User extends Component<any, UserState> {
moderates() { moderates() {
return ( return (
<div> <div>
{this.state.userRes.moderates.length > 0 && ( {this.state.personRes.moderates.length > 0 && (
<div class="card border-secondary mb-3"> <div class="card border-secondary mb-3">
<div class="card-body"> <div class="card-body">
<h5>{i18n.t("moderates")}</h5> <h5>{i18n.t("moderates")}</h5>
<ul class="list-unstyled mb-0"> <ul class="list-unstyled mb-0">
{this.state.userRes.moderates.map(cmv => ( {this.state.personRes.moderates.map(cmv => (
<li> <li>
<CommunityLink community={cmv.community} /> <CommunityLink community={cmv.community} />
</li> </li>
@ -866,12 +872,12 @@ export class User extends Component<any, UserState> {
follows() { follows() {
return ( return (
<div> <div>
{this.state.userRes.follows.length > 0 && ( {this.state.personRes.follows.length > 0 && (
<div class="card border-secondary mb-3"> <div class="card border-secondary mb-3">
<div class="card-body"> <div class="card-body">
<h5>{i18n.t("subscribed")}</h5> <h5>{i18n.t("subscribed")}</h5>
<ul class="list-unstyled mb-0"> <ul class="list-unstyled mb-0">
{this.state.userRes.follows.map(cfv => ( {this.state.personRes.follows.map(cfv => (
<li> <li>
<CommunityLink community={cfv.community} /> <CommunityLink community={cfv.community} />
</li> </li>
@ -886,12 +892,12 @@ export class User extends Component<any, UserState> {
updateUrl(paramUpdates: UrlParams) { updateUrl(paramUpdates: UrlParams) {
const page = paramUpdates.page || this.state.page; const page = paramUpdates.page || this.state.page;
const viewStr = paramUpdates.view || UserDetailsView[this.state.view]; const viewStr = paramUpdates.view || PersonDetailsView[this.state.view];
const sortStr = paramUpdates.sort || this.state.sort; const sortStr = paramUpdates.sort || this.state.sort;
let typeView = this.state.userName let typeView = this.state.userName
? `/u/${this.state.userName}` ? `/u/${this.state.userName}`
: `/user/${this.state.userId}`; : `/user/${this.state.personId}`;
this.props.history.push( this.props.history.push(
`${typeView}/view/${viewStr}/sort/${sortStr}/page/${page}` `${typeView}/view/${viewStr}/sort/${sortStr}/page/${page}`
@ -909,36 +915,37 @@ export class User extends Component<any, UserState> {
this.updateUrl({ sort: val, page: 1 }); this.updateUrl({ sort: val, page: 1 });
} }
handleViewChange(i: User, event: any) { handleViewChange(i: Person, event: any) {
i.updateUrl({ i.updateUrl({
view: UserDetailsView[Number(event.target.value)], view: PersonDetailsView[Number(event.target.value)],
page: 1, page: 1,
}); });
} }
handleUserSettingsShowNsfwChange(i: User, event: any) { handleUserSettingsShowNsfwChange(i: Person, event: any) {
i.state.userSettingsForm.show_nsfw = event.target.checked; i.state.userSettingsForm.show_nsfw = event.target.checked;
i.setState(i.state); i.setState(i.state);
} }
handleUserSettingsShowAvatarsChange(i: User, event: any) { handleUserSettingsShowAvatarsChange(i: Person, event: any) {
i.state.userSettingsForm.show_avatars = event.target.checked; i.state.userSettingsForm.show_avatars = event.target.checked;
UserService.Instance.user.show_avatars = event.target.checked; // Just for instant updates UserService.Instance.localUserView.local_user.show_avatars =
event.target.checked; // Just for instant updates
i.setState(i.state); i.setState(i.state);
} }
handleUserSettingsSendNotificationsToEmailChange(i: User, event: any) { handleUserSettingsSendNotificationsToEmailChange(i: Person, event: any) {
i.state.userSettingsForm.send_notifications_to_email = event.target.checked; i.state.userSettingsForm.send_notifications_to_email = event.target.checked;
i.setState(i.state); i.setState(i.state);
} }
handleUserSettingsThemeChange(i: User, event: any) { handleUserSettingsThemeChange(i: Person, event: any) {
i.state.userSettingsForm.theme = event.target.value; i.state.userSettingsForm.theme = event.target.value;
setTheme(event.target.value, true); setTheme(event.target.value, true);
i.setState(i.state); i.setState(i.state);
} }
handleUserSettingsLangChange(i: User, event: any) { handleUserSettingsLangChange(i: Person, event: any) {
i.state.userSettingsForm.lang = event.target.value; i.state.userSettingsForm.lang = event.target.value;
i18n.changeLanguage(getLanguage(i.state.userSettingsForm.lang)); i18n.changeLanguage(getLanguage(i.state.userSettingsForm.lang));
i.setState(i.state); i.setState(i.state);
@ -958,7 +965,7 @@ export class User extends Component<any, UserState> {
this.setState(this.state); this.setState(this.state);
} }
handleUserSettingsEmailChange(i: User, event: any) { handleUserSettingsEmailChange(i: Person, event: any) {
i.state.userSettingsForm.email = event.target.value; i.state.userSettingsForm.email = event.target.value;
i.setState(i.state); i.setState(i.state);
} }
@ -988,23 +995,23 @@ export class User extends Component<any, UserState> {
this.setState(this.state); this.setState(this.state);
} }
handleUserSettingsPreferredUsernameChange(i: User, event: any) { handleUserSettingsPreferredUsernameChange(i: Person, event: any) {
i.state.userSettingsForm.preferred_username = event.target.value; i.state.userSettingsForm.preferred_username = event.target.value;
i.setState(i.state); i.setState(i.state);
} }
handleUserSettingsMatrixUserIdChange(i: User, event: any) { handleUserSettingsMatrixUserIdChange(i: Person, event: any) {
i.state.userSettingsForm.matrix_user_id = event.target.value; i.state.userSettingsForm.matrix_user_id = event.target.value;
if ( if (
i.state.userSettingsForm.matrix_user_id == "" && i.state.userSettingsForm.matrix_user_id == "" &&
!i.state.userRes.user_view.user.matrix_user_id !UserService.Instance.localUserView.person.matrix_user_id
) { ) {
i.state.userSettingsForm.matrix_user_id = undefined; i.state.userSettingsForm.matrix_user_id = undefined;
} }
i.setState(i.state); i.setState(i.state);
} }
handleUserSettingsNewPasswordChange(i: User, event: any) { handleUserSettingsNewPasswordChange(i: Person, event: any) {
i.state.userSettingsForm.new_password = event.target.value; i.state.userSettingsForm.new_password = event.target.value;
if (i.state.userSettingsForm.new_password == "") { if (i.state.userSettingsForm.new_password == "") {
i.state.userSettingsForm.new_password = undefined; i.state.userSettingsForm.new_password = undefined;
@ -1012,7 +1019,7 @@ export class User extends Component<any, UserState> {
i.setState(i.state); i.setState(i.state);
} }
handleUserSettingsNewPasswordVerifyChange(i: User, event: any) { handleUserSettingsNewPasswordVerifyChange(i: Person, event: any) {
i.state.userSettingsForm.new_password_verify = event.target.value; i.state.userSettingsForm.new_password_verify = event.target.value;
if (i.state.userSettingsForm.new_password_verify == "") { if (i.state.userSettingsForm.new_password_verify == "") {
i.state.userSettingsForm.new_password_verify = undefined; i.state.userSettingsForm.new_password_verify = undefined;
@ -1020,7 +1027,7 @@ export class User extends Component<any, UserState> {
i.setState(i.state); i.setState(i.state);
} }
handleUserSettingsOldPasswordChange(i: User, event: any) { handleUserSettingsOldPasswordChange(i: Person, event: any) {
i.state.userSettingsForm.old_password = event.target.value; i.state.userSettingsForm.old_password = event.target.value;
if (i.state.userSettingsForm.old_password == "") { if (i.state.userSettingsForm.old_password == "") {
i.state.userSettingsForm.old_password = undefined; i.state.userSettingsForm.old_password = undefined;
@ -1028,7 +1035,7 @@ export class User extends Component<any, UserState> {
i.setState(i.state); i.setState(i.state);
} }
handleUserSettingsSubmit(i: User, event: any) { handleUserSettingsSubmit(i: Person, event: any) {
event.preventDefault(); event.preventDefault();
i.state.userSettingsLoading = true; i.state.userSettingsLoading = true;
i.setState(i.state); i.setState(i.state);
@ -1038,23 +1045,23 @@ export class User extends Component<any, UserState> {
); );
} }
handleDeleteAccountShowConfirmToggle(i: User, event: any) { handleDeleteAccountShowConfirmToggle(i: Person, event: any) {
event.preventDefault(); event.preventDefault();
i.state.deleteAccountShowConfirm = !i.state.deleteAccountShowConfirm; i.state.deleteAccountShowConfirm = !i.state.deleteAccountShowConfirm;
i.setState(i.state); i.setState(i.state);
} }
handleDeleteAccountPasswordChange(i: User, event: any) { handleDeleteAccountPasswordChange(i: Person, event: any) {
i.state.deleteAccountForm.password = event.target.value; i.state.deleteAccountForm.password = event.target.value;
i.setState(i.state); i.setState(i.state);
} }
handleLogoutClick(i: User) { handleLogoutClick(i: Person) {
UserService.Instance.logout(); UserService.Instance.logout();
i.context.router.history.push("/"); i.context.router.history.push("/");
} }
handleDeleteAccount(i: User, event: any) { handleDeleteAccount(i: Person, event: any) {
event.preventDefault(); event.preventDefault();
i.state.deleteAccountLoading = true; i.state.deleteAccountLoading = true;
i.setState(i.state); i.setState(i.state);
@ -1068,27 +1075,33 @@ export class User extends Component<any, UserState> {
setUserInfo() { setUserInfo() {
if (this.isCurrentUser) { if (this.isCurrentUser) {
this.state.userSettingsForm.show_nsfw = this.state.userSettingsForm.show_nsfw =
UserService.Instance.user.show_nsfw; UserService.Instance.localUserView.local_user.show_nsfw;
this.state.userSettingsForm.theme = UserService.Instance.user.theme this.state.userSettingsForm.theme = UserService.Instance.localUserView
? UserService.Instance.user.theme .local_user.theme
? UserService.Instance.localUserView.local_user.theme
: "browser"; : "browser";
this.state.userSettingsForm.default_sort_type = this.state.userSettingsForm.default_sort_type =
UserService.Instance.user.default_sort_type; UserService.Instance.localUserView.local_user.default_sort_type;
this.state.userSettingsForm.default_listing_type = this.state.userSettingsForm.default_listing_type =
UserService.Instance.user.default_listing_type; UserService.Instance.localUserView.local_user.default_listing_type;
this.state.userSettingsForm.lang = UserService.Instance.user.lang; this.state.userSettingsForm.lang =
this.state.userSettingsForm.avatar = UserService.Instance.user.avatar; UserService.Instance.localUserView.local_user.lang;
this.state.userSettingsForm.banner = UserService.Instance.user.banner; this.state.userSettingsForm.avatar =
UserService.Instance.localUserView.person.avatar;
this.state.userSettingsForm.banner =
UserService.Instance.localUserView.person.banner;
this.state.userSettingsForm.preferred_username = this.state.userSettingsForm.preferred_username =
UserService.Instance.user.preferred_username; UserService.Instance.localUserView.person.preferred_username;
this.state.userSettingsForm.show_avatars = this.state.userSettingsForm.show_avatars =
UserService.Instance.user.show_avatars; UserService.Instance.localUserView.local_user.show_avatars;
this.state.userSettingsForm.email = UserService.Instance.user.email; this.state.userSettingsForm.email =
this.state.userSettingsForm.bio = UserService.Instance.user.bio; UserService.Instance.localUserView.local_user.email;
this.state.userSettingsForm.bio =
UserService.Instance.localUserView.person.bio;
this.state.userSettingsForm.send_notifications_to_email = this.state.userSettingsForm.send_notifications_to_email =
UserService.Instance.user.send_notifications_to_email; UserService.Instance.localUserView.local_user.send_notifications_to_email;
this.state.userSettingsForm.matrix_user_id = this.state.userSettingsForm.matrix_user_id =
UserService.Instance.user.matrix_user_id; UserService.Instance.localUserView.person.matrix_user_id;
} }
} }
@ -1106,12 +1119,12 @@ export class User extends Component<any, UserState> {
return; return;
} else if (msg.reconnect) { } else if (msg.reconnect) {
this.fetchUserData(); this.fetchUserData();
} else if (op == UserOperation.GetUserDetails) { } else if (op == UserOperation.GetPersonDetails) {
// Since the UserDetails contains posts/comments as well as some general user info we listen here as well // Since the PersonDetails contains posts/comments as well as some general user info we listen here as well
// and set the parent state if it is not set or differs // and set the parent state if it is not set or differs
// TODO this might need to get abstracted // TODO this might need to get abstracted
let data = wsJsonToRes<GetUserDetailsResponse>(msg).data; let data = wsJsonToRes<GetPersonDetailsResponse>(msg).data;
this.state.userRes = data; this.state.personRes = data;
this.setUserInfo(); this.setUserInfo();
this.state.loading = false; this.state.loading = false;
this.setState(this.state); this.setState(this.state);
@ -1119,10 +1132,10 @@ export class User extends Component<any, UserState> {
} else if (op == UserOperation.SaveUserSettings) { } else if (op == UserOperation.SaveUserSettings) {
let data = wsJsonToRes<LoginResponse>(msg).data; let data = wsJsonToRes<LoginResponse>(msg).data;
UserService.Instance.login(data); UserService.Instance.login(data);
this.state.userRes.user_view.user.bio = this.state.userSettingsForm.bio; this.state.personRes.person_view.person.bio = this.state.userSettingsForm.bio;
this.state.userRes.user_view.user.preferred_username = this.state.userSettingsForm.preferred_username; this.state.personRes.person_view.person.preferred_username = this.state.userSettingsForm.preferred_username;
this.state.userRes.user_view.user.banner = this.state.userSettingsForm.banner; this.state.personRes.person_view.person.banner = this.state.userSettingsForm.banner;
this.state.userRes.user_view.user.avatar = this.state.userSettingsForm.avatar; this.state.personRes.person_view.person.avatar = this.state.userSettingsForm.avatar;
this.state.userSettingsLoading = false; this.state.userSettingsLoading = false;
this.setState(this.state); this.setState(this.state);
@ -1139,7 +1152,7 @@ export class User extends Component<any, UserState> {
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.CreateCommentLike) { } else if (op == UserOperation.CreateCommentLike) {
let data = wsJsonToRes<CommentResponse>(msg).data; let data = wsJsonToRes<CommentResponse>(msg).data;
createCommentLikeRes(data.comment_view, this.state.userRes.comments); createCommentLikeRes(data.comment_view, this.state.personRes.comments);
this.setState(this.state); this.setState(this.state);
} else if ( } else if (
op == UserOperation.EditComment || op == UserOperation.EditComment ||
@ -1147,19 +1160,20 @@ export class User extends Component<any, UserState> {
op == UserOperation.RemoveComment op == UserOperation.RemoveComment
) { ) {
let data = wsJsonToRes<CommentResponse>(msg).data; let data = wsJsonToRes<CommentResponse>(msg).data;
editCommentRes(data.comment_view, this.state.userRes.comments); editCommentRes(data.comment_view, this.state.personRes.comments);
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.CreateComment) { } else if (op == UserOperation.CreateComment) {
let data = wsJsonToRes<CommentResponse>(msg).data; let data = wsJsonToRes<CommentResponse>(msg).data;
if ( if (
UserService.Instance.user && UserService.Instance.localUserView &&
data.comment_view.creator.id == UserService.Instance.user.id data.comment_view.creator.id ==
UserService.Instance.localUserView.person.id
) { ) {
toast(i18n.t("reply_sent")); toast(i18n.t("reply_sent"));
} }
} else if (op == UserOperation.SaveComment) { } else if (op == UserOperation.SaveComment) {
let data = wsJsonToRes<CommentResponse>(msg).data; let data = wsJsonToRes<CommentResponse>(msg).data;
saveCommentRes(data.comment_view, this.state.userRes.comments); saveCommentRes(data.comment_view, this.state.personRes.comments);
this.setState(this.state); this.setState(this.state);
} else if ( } else if (
op == UserOperation.EditPost || op == UserOperation.EditPost ||
@ -1170,19 +1184,19 @@ export class User extends Component<any, UserState> {
op == UserOperation.SavePost op == UserOperation.SavePost
) { ) {
let data = wsJsonToRes<PostResponse>(msg).data; let data = wsJsonToRes<PostResponse>(msg).data;
editPostFindRes(data.post_view, this.state.userRes.posts); editPostFindRes(data.post_view, this.state.personRes.posts);
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.CreatePostLike) { } else if (op == UserOperation.CreatePostLike) {
let data = wsJsonToRes<PostResponse>(msg).data; let data = wsJsonToRes<PostResponse>(msg).data;
createPostLikeFindRes(data.post_view, this.state.userRes.posts); createPostLikeFindRes(data.post_view, this.state.personRes.posts);
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.BanUser) { } else if (op == UserOperation.BanPerson) {
let data = wsJsonToRes<BanUserResponse>(msg).data; let data = wsJsonToRes<BanPersonResponse>(msg).data;
this.state.userRes.comments this.state.personRes.comments
.filter(c => c.creator.id == data.user_view.user.id) .filter(c => c.creator.id == data.person_view.person.id)
.forEach(c => (c.creator.banned = data.banned)); .forEach(c => (c.creator.banned = data.banned));
this.state.userRes.posts this.state.personRes.posts
.filter(c => c.creator.id == data.user_view.user.id) .filter(c => c.creator.id == data.person_view.person.id)
.forEach(c => (c.creator.banned = data.banned)); .forEach(c => (c.creator.banned = data.banned));
this.setState(this.state); this.setState(this.state);
} }

View file

@ -191,7 +191,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
<label <label
htmlFor="file-upload" htmlFor="file-upload"
className={`${ className={`${
UserService.Instance.user && "pointer" UserService.Instance.localUserView && "pointer"
} d-inline-block float-right text-muted font-weight-bold`} } d-inline-block float-right text-muted font-weight-bold`}
data-tippy-content={i18n.t("upload_image")} data-tippy-content={i18n.t("upload_image")}
> >
@ -203,7 +203,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
accept="image/*,video/*" accept="image/*,video/*"
name="file" name="file"
class="d-none" class="d-none"
disabled={!UserService.Instance.user} disabled={!UserService.Instance.localUserView}
onChange={linkEvent(this, this.handleImageUpload)} onChange={linkEvent(this, this.handleImageUpload)}
/> />
</form> </form>
@ -613,13 +613,19 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
return; return;
} else if (op == UserOperation.CreatePost) { } else if (op == UserOperation.CreatePost) {
let data = wsJsonToRes<PostResponse>(msg).data; let data = wsJsonToRes<PostResponse>(msg).data;
if (data.post_view.creator.id == UserService.Instance.user.id) { if (
data.post_view.creator.id ==
UserService.Instance.localUserView.person.id
) {
this.state.loading = false; this.state.loading = false;
this.props.onCreate(data.post_view); this.props.onCreate(data.post_view);
} }
} else if (op == UserOperation.EditPost) { } else if (op == UserOperation.EditPost) {
let data = wsJsonToRes<PostResponse>(msg).data; let data = wsJsonToRes<PostResponse>(msg).data;
if (data.post_view.creator.id == UserService.Instance.user.id) { if (
data.post_view.creator.id ==
UserService.Instance.localUserView.person.id
) {
this.state.loading = false; this.state.loading = false;
this.props.onEdit(data.post_view); this.props.onEdit(data.post_view);
} }

View file

@ -9,9 +9,9 @@ import {
LockPost, LockPost,
StickyPost, StickyPost,
SavePost, SavePost,
UserViewSafe, PersonViewSafe,
BanFromCommunity, BanFromCommunity,
BanUser, BanPerson,
AddModToCommunity, AddModToCommunity,
AddAdmin, AddAdmin,
TransferSite, TransferSite,
@ -22,7 +22,7 @@ import { BanType } from "../interfaces";
import { MomentTime } from "./moment-time"; import { MomentTime } from "./moment-time";
import { PostForm } from "./post-form"; import { PostForm } from "./post-form";
import { IFramelyCard } from "./iframely-card"; import { IFramelyCard } from "./iframely-card";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
import { PictrsImage } from "./pictrs-image"; import { PictrsImage } from "./pictrs-image";
import { Icon } from "./icon"; import { Icon } from "./icon";
@ -70,7 +70,7 @@ interface PostListingProps {
showCommunity?: boolean; showCommunity?: boolean;
showBody?: boolean; showBody?: boolean;
moderators?: CommunityModeratorView[]; moderators?: CommunityModeratorView[];
admins?: UserViewSafe[]; admins?: PersonViewSafe[];
enableDownvotes: boolean; enableDownvotes: boolean;
enableNsfw: boolean; enableNsfw: boolean;
} }
@ -270,7 +270,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
return ( return (
<ul class="list-inline mb-1 text-muted small"> <ul class="list-inline mb-1 text-muted small">
<li className="list-inline-item"> <li className="list-inline-item">
<UserListing user={post_view.creator} /> <PersonListing person={post_view.creator} />
{this.isMod && ( {this.isMod && (
<span className="mx-1 badge badge-light">{i18n.t("mod")}</span> <span className="mx-1 badge badge-light">{i18n.t("mod")}</span>
@ -599,7 +599,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
postActions(mobile = false) { postActions(mobile = false) {
let post_view = this.props.post_view; let post_view = this.props.post_view;
return ( return (
UserService.Instance.user && ( UserService.Instance.localUserView && (
<> <>
{this.props.showBody && ( {this.props.showBody && (
<> <>
@ -1083,8 +1083,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
private get myPost(): boolean { private get myPost(): boolean {
return ( return (
UserService.Instance.user && UserService.Instance.localUserView &&
this.props.post_view.creator.id == UserService.Instance.user.id this.props.post_view.creator.id ==
UserService.Instance.localUserView.person.id
); );
} }
@ -1102,7 +1103,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
return ( return (
this.props.admins && this.props.admins &&
isMod( isMod(
this.props.admins.map(a => a.user.id), this.props.admins.map(a => a.person.id),
this.props.post_view.creator.id this.props.post_view.creator.id
) )
); );
@ -1111,11 +1112,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
get canMod(): boolean { get canMod(): boolean {
if (this.props.admins && this.props.moderators) { if (this.props.admins && this.props.moderators) {
let adminsThenMods = this.props.admins let adminsThenMods = this.props.admins
.map(a => a.user.id) .map(a => a.person.id)
.concat(this.props.moderators.map(m => m.moderator.id)); .concat(this.props.moderators.map(m => m.moderator.id));
return canMod( return canMod(
UserService.Instance.user, UserService.Instance.localUserView,
adminsThenMods, adminsThenMods,
this.props.post_view.creator.id this.props.post_view.creator.id
); );
@ -1127,11 +1128,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
get canModOnSelf(): boolean { get canModOnSelf(): boolean {
if (this.props.admins && this.props.moderators) { if (this.props.admins && this.props.moderators) {
let adminsThenMods = this.props.admins let adminsThenMods = this.props.admins
.map(a => a.user.id) .map(a => a.person.id)
.concat(this.props.moderators.map(m => m.moderator.id)); .concat(this.props.moderators.map(m => m.moderator.id));
return canMod( return canMod(
UserService.Instance.user, UserService.Instance.localUserView,
adminsThenMods, adminsThenMods,
this.props.post_view.creator.id, this.props.post_view.creator.id,
true true
@ -1145,8 +1146,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
return ( return (
this.props.admins && this.props.admins &&
canMod( canMod(
UserService.Instance.user, UserService.Instance.localUserView,
this.props.admins.map(a => a.user.id), this.props.admins.map(a => a.person.id),
this.props.post_view.creator.id this.props.post_view.creator.id
) )
); );
@ -1155,24 +1156,28 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
get amCommunityCreator(): boolean { get amCommunityCreator(): boolean {
return ( return (
this.props.moderators && this.props.moderators &&
UserService.Instance.user && UserService.Instance.localUserView &&
this.props.post_view.creator.id != UserService.Instance.user.id && this.props.post_view.creator.id !=
UserService.Instance.user.id == this.props.moderators[0].moderator.id UserService.Instance.localUserView.person.id &&
UserService.Instance.localUserView.person.id ==
this.props.moderators[0].moderator.id
); );
} }
get amSiteCreator(): boolean { get amSiteCreator(): boolean {
return ( return (
this.props.admins && this.props.admins &&
UserService.Instance.user && UserService.Instance.localUserView &&
this.props.post_view.creator.id != UserService.Instance.user.id && this.props.post_view.creator.id !=
UserService.Instance.user.id == this.props.admins[0].user.id UserService.Instance.localUserView.person.id &&
UserService.Instance.localUserView.person.id ==
this.props.admins[0].person.id
); );
} }
handlePostLike(i: PostListing, event: any) { handlePostLike(i: PostListing, event: any) {
event.preventDefault(); event.preventDefault();
if (!UserService.Instance.user) { if (!UserService.Instance.localUserView) {
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }
@ -1205,7 +1210,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
handlePostDisLike(i: PostListing, event: any) { handlePostDisLike(i: PostListing, event: any) {
event.preventDefault(); event.preventDefault();
if (!UserService.Instance.user) { if (!UserService.Instance.localUserView) {
this.context.router.history.push(`/login`); this.context.router.history.push(`/login`);
} }
@ -1377,7 +1382,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
i.state.removeData = false; i.state.removeData = false;
} }
let form: BanFromCommunity = { let form: BanFromCommunity = {
user_id: i.props.post_view.creator.id, person_id: i.props.post_view.creator.id,
community_id: i.props.post_view.community.id, community_id: i.props.post_view.community.id,
ban, ban,
remove_data: i.state.removeData, remove_data: i.state.removeData,
@ -1392,15 +1397,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
if (ban == false) { if (ban == false) {
i.state.removeData = false; i.state.removeData = false;
} }
let form: BanUser = { let form: BanPerson = {
user_id: i.props.post_view.creator.id, person_id: i.props.post_view.creator.id,
ban, ban,
remove_data: i.state.removeData, remove_data: i.state.removeData,
reason: i.state.banReason, reason: i.state.banReason,
expires: getUnixTime(i.state.banExpires), expires: getUnixTime(i.state.banExpires),
auth: authField(), auth: authField(),
}; };
WebSocketService.Instance.send(wsClient.banUser(form)); WebSocketService.Instance.send(wsClient.banPerson(form));
} }
i.state.showBanDialog = false; i.state.showBanDialog = false;
@ -1409,7 +1414,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
handleAddModToCommunity(i: PostListing) { handleAddModToCommunity(i: PostListing) {
let form: AddModToCommunity = { let form: AddModToCommunity = {
user_id: i.props.post_view.creator.id, person_id: i.props.post_view.creator.id,
community_id: i.props.post_view.community.id, community_id: i.props.post_view.community.id,
added: !i.isMod, added: !i.isMod,
auth: authField(), auth: authField(),
@ -1420,7 +1425,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
handleAddAdmin(i: PostListing) { handleAddAdmin(i: PostListing) {
let form: AddAdmin = { let form: AddAdmin = {
user_id: i.props.post_view.creator.id, person_id: i.props.post_view.creator.id,
added: !i.isAdmin, added: !i.isAdmin,
auth: authField(), auth: authField(),
}; };
@ -1441,7 +1446,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
handleTransferCommunity(i: PostListing) { handleTransferCommunity(i: PostListing) {
let form: TransferCommunity = { let form: TransferCommunity = {
community_id: i.props.post_view.community.id, community_id: i.props.post_view.community.id,
user_id: i.props.post_view.creator.id, person_id: i.props.post_view.creator.id,
auth: authField(), auth: authField(),
}; };
WebSocketService.Instance.send(wsClient.transferCommunity(form)); WebSocketService.Instance.send(wsClient.transferCommunity(form));
@ -1461,7 +1466,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
handleTransferSite(i: PostListing) { handleTransferSite(i: PostListing) {
let form: TransferSite = { let form: TransferSite = {
user_id: i.props.post_view.creator.id, person_id: i.props.post_view.creator.id,
auth: authField(), auth: authField(),
}; };
WebSocketService.Instance.send(wsClient.transferSite(form)); WebSocketService.Instance.send(wsClient.transferSite(form));

View file

@ -11,7 +11,7 @@ import {
CommentResponse, CommentResponse,
CommunityResponse, CommunityResponse,
BanFromCommunityResponse, BanFromCommunityResponse,
BanUserResponse, BanPersonResponse,
AddModToCommunityResponse, AddModToCommunityResponse,
AddAdminResponse, AddAdminResponse,
SearchType, SearchType,
@ -207,13 +207,13 @@ export class Post extends Component<any, PostState> {
let parent = this.state.postRes.comments.find( let parent = this.state.postRes.comments.find(
c => found.comment.parent_id == c.comment.id c => found.comment.parent_id == c.comment.id
); );
let parent_user_id = parent let parent_person_id = parent
? parent.creator.id ? parent.creator.id
: this.state.postRes.post_view.creator.id; : this.state.postRes.post_view.creator.id;
if ( if (
UserService.Instance.user && UserService.Instance.localUserView &&
UserService.Instance.user.id == parent_user_id UserService.Instance.localUserView.person.id == parent_person_id
) { ) {
let form: MarkCommentAsRead = { let form: MarkCommentAsRead = {
comment_id: found.comment.id, comment_id: found.comment.id,
@ -522,9 +522,11 @@ export class Post extends Component<any, PostState> {
} else if (op == UserOperation.BanFromCommunity) { } else if (op == UserOperation.BanFromCommunity) {
let data = wsJsonToRes<BanFromCommunityResponse>(msg).data; let data = wsJsonToRes<BanFromCommunityResponse>(msg).data;
this.state.postRes.comments this.state.postRes.comments
.filter(c => c.creator.id == data.user_view.user.id) .filter(c => c.creator.id == data.person_view.person.id)
.forEach(c => (c.creator_banned_from_community = data.banned)); .forEach(c => (c.creator_banned_from_community = data.banned));
if (this.state.postRes.post_view.creator.id == data.user_view.user.id) { if (
this.state.postRes.post_view.creator.id == data.person_view.person.id
) {
this.state.postRes.post_view.creator_banned_from_community = this.state.postRes.post_view.creator_banned_from_community =
data.banned; data.banned;
} }
@ -533,12 +535,14 @@ export class Post extends Component<any, PostState> {
let data = wsJsonToRes<AddModToCommunityResponse>(msg).data; let data = wsJsonToRes<AddModToCommunityResponse>(msg).data;
this.state.postRes.moderators = data.moderators; this.state.postRes.moderators = data.moderators;
this.setState(this.state); this.setState(this.state);
} else if (op == UserOperation.BanUser) { } else if (op == UserOperation.BanPerson) {
let data = wsJsonToRes<BanUserResponse>(msg).data; let data = wsJsonToRes<BanPersonResponse>(msg).data;
this.state.postRes.comments this.state.postRes.comments
.filter(c => c.creator.id == data.user_view.user.id) .filter(c => c.creator.id == data.person_view.person.id)
.forEach(c => (c.creator.banned = data.banned)); .forEach(c => (c.creator.banned = data.banned));
if (this.state.postRes.post_view.creator.id == data.user_view.user.id) { if (
this.state.postRes.post_view.creator.id == data.person_view.person.id
) {
this.state.postRes.post_view.creator.banned = data.banned; this.state.postRes.post_view.creator.banned = data.banned;
} }
this.setState(this.state); this.setState(this.state);

View file

@ -6,7 +6,7 @@ import {
EditPrivateMessage, EditPrivateMessage,
PrivateMessageView, PrivateMessageView,
PrivateMessageResponse, PrivateMessageResponse,
UserSafe, PersonSafe,
UserOperation, UserOperation,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { WebSocketService } from "../services"; import { WebSocketService } from "../services";
@ -21,14 +21,14 @@ import {
wsClient, wsClient,
authField, authField,
} from "../utils"; } from "../utils";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { MarkdownTextArea } from "./markdown-textarea"; import { MarkdownTextArea } from "./markdown-textarea";
import { Icon, Spinner } from "./icon"; import { Icon, Spinner } from "./icon";
import { i18n } from "../i18next"; import { i18n } from "../i18next";
import { T } from "inferno-i18next"; import { T } from "inferno-i18next";
interface PrivateMessageFormProps { interface PrivateMessageFormProps {
recipient: UserSafe; recipient: PersonSafe;
privateMessage?: PrivateMessageView; // If a pm is given, that means this is an edit privateMessage?: PrivateMessageView; // If a pm is given, that means this is an edit
onCancel?(): any; onCancel?(): any;
onCreate?(message: PrivateMessageView): any; onCreate?(message: PrivateMessageView): any;
@ -108,7 +108,7 @@ export class PrivateMessageForm extends Component<
</label> </label>
<div class="col-sm-10 form-control-plaintext"> <div class="col-sm-10 form-control-plaintext">
<UserListing user={this.props.recipient} /> <PersonListing person={this.props.recipient} />
</div> </div>
</div> </div>
)} )}

View file

@ -3,13 +3,13 @@ import {
PrivateMessageView, PrivateMessageView,
DeletePrivateMessage, DeletePrivateMessage,
MarkPrivateMessageAsRead, MarkPrivateMessageAsRead,
UserSafe, PersonSafe,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { WebSocketService, UserService } from "../services"; import { WebSocketService, UserService } from "../services";
import { authField, mdToHtml, toast, wsClient } from "../utils"; import { authField, mdToHtml, toast, wsClient } from "../utils";
import { MomentTime } from "./moment-time"; import { MomentTime } from "./moment-time";
import { PrivateMessageForm } from "./private-message-form"; import { PrivateMessageForm } from "./private-message-form";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { Icon } from "./icon"; import { Icon } from "./icon";
import { i18n } from "../i18next"; import { i18n } from "../i18next";
@ -48,15 +48,16 @@ export class PrivateMessage extends Component<
get mine(): boolean { get mine(): boolean {
return ( return (
UserService.Instance.user && UserService.Instance.localUserView &&
UserService.Instance.user.id == this.props.private_message_view.creator.id UserService.Instance.localUserView.person.id ==
this.props.private_message_view.creator.id
); );
} }
render() { render() {
let message_view = this.props.private_message_view; let message_view = this.props.private_message_view;
// TODO check this again // TODO check this again
let userOther: UserSafe = this.mine let otherPerson: PersonSafe = this.mine
? message_view.recipient ? message_view.recipient
: message_view.creator; : message_view.creator;
@ -69,7 +70,7 @@ export class PrivateMessage extends Component<
{this.mine ? i18n.t("to") : i18n.t("from")} {this.mine ? i18n.t("to") : i18n.t("from")}
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item">
<UserListing user={userOther} /> <PersonListing person={otherPerson} />
</li> </li>
<li className="list-inline-item"> <li className="list-inline-item">
<span> <span>
@ -92,7 +93,7 @@ export class PrivateMessage extends Component<
</ul> </ul>
{this.state.showEdit && ( {this.state.showEdit && (
<PrivateMessageForm <PrivateMessageForm
recipient={userOther} recipient={otherPerson}
privateMessage={message_view} privateMessage={message_view}
onEdit={this.handlePrivateMessageEdit} onEdit={this.handlePrivateMessageEdit}
onCreate={this.handlePrivateMessageCreate} onCreate={this.handlePrivateMessageCreate}
@ -206,7 +207,7 @@ export class PrivateMessage extends Component<
</div> </div>
{this.state.showReply && ( {this.state.showReply && (
<PrivateMessageForm <PrivateMessageForm
recipient={userOther} recipient={otherPerson}
onCreate={this.handlePrivateMessageCreate} onCreate={this.handlePrivateMessageCreate}
/> />
)} )}
@ -272,8 +273,8 @@ export class PrivateMessage extends Component<
handlePrivateMessageCreate(message: PrivateMessageView) { handlePrivateMessageCreate(message: PrivateMessageView) {
if ( if (
UserService.Instance.user && UserService.Instance.localUserView &&
message.creator.id == UserService.Instance.user.id message.creator.id == UserService.Instance.localUserView.person.id
) { ) {
this.state.showReply = false; this.state.showReply = false;
this.setState(this.state); this.setState(this.state);

View file

@ -5,7 +5,7 @@ import {
PostView, PostView,
CommentView, CommentView,
CommunityView, CommunityView,
UserViewSafe, PersonViewSafe,
SortType, SortType,
Search as SearchForm, Search as SearchForm,
SearchResponse, SearchResponse,
@ -36,7 +36,7 @@ import {
import { PostListing } from "./post-listing"; import { PostListing } from "./post-listing";
import { HtmlTags } from "./html-tags"; import { HtmlTags } from "./html-tags";
import { Spinner } from "./icon"; import { Spinner } from "./icon";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
import { SortSelect } from "./sort-select"; import { SortSelect } from "./sort-select";
import { CommentNodes } from "./comment-nodes"; import { CommentNodes } from "./comment-nodes";
@ -257,7 +257,7 @@ export class Search extends Component<any, SearchState> {
all() { all() {
let combined: { let combined: {
type_: string; type_: string;
data: CommentView | PostView | CommunityView | UserViewSafe; data: CommentView | PostView | CommunityView | PersonViewSafe;
published: string; published: string;
}[] = []; }[] = [];
let comments = this.state.searchResponse.comments.map(e => { let comments = this.state.searchResponse.comments.map(e => {
@ -274,7 +274,7 @@ export class Search extends Component<any, SearchState> {
}; };
}); });
let users = this.state.searchResponse.users.map(e => { let users = this.state.searchResponse.users.map(e => {
return { type_: "users", data: e, published: e.user.published }; return { type_: "users", data: e, published: e.person.published };
}); });
combined.push(...comments); combined.push(...comments);
@ -290,10 +290,10 @@ export class Search extends Component<any, SearchState> {
(a, b) => (a, b) =>
((b.data as CommentView | PostView).counts.score | ((b.data as CommentView | PostView).counts.score |
(b.data as CommunityView).counts.subscribers | (b.data as CommunityView).counts.subscribers |
(b.data as UserViewSafe).counts.comment_score) - (b.data as PersonViewSafe).counts.comment_score) -
((a.data as CommentView | PostView).counts.score | ((a.data as CommentView | PostView).counts.score |
(a.data as CommunityView).counts.subscribers | (a.data as CommunityView).counts.subscribers |
(a.data as UserViewSafe).counts.comment_score) (a.data as PersonViewSafe).counts.comment_score)
); );
} }
@ -324,7 +324,7 @@ export class Search extends Component<any, SearchState> {
<div>{this.communityListing(i.data as CommunityView)}</div> <div>{this.communityListing(i.data as CommunityView)}</div>
)} )}
{i.type_ == "users" && ( {i.type_ == "users" && (
<div>{this.userListing(i.data as UserViewSafe)}</div> <div>{this.userListing(i.data as PersonViewSafe)}</div>
)} )}
</div> </div>
</div> </div>
@ -390,13 +390,13 @@ export class Search extends Component<any, SearchState> {
); );
} }
userListing(user_view: UserViewSafe) { userListing(person_view: PersonViewSafe) {
return [ return [
<span> <span>
<UserListing user={user_view.user} showApubName /> <PersonListing person={person_view.person} showApubName />
</span>, </span>,
<span>{` - ${i18n.t("number_of_comments", { <span>{` - ${i18n.t("number_of_comments", {
count: user_view.counts.comment_count, count: person_view.counts.comment_count,
})}`}</span>, })}`}</span>,
]; ];
} }

View file

@ -6,13 +6,13 @@ import {
FollowCommunity, FollowCommunity,
DeleteCommunity, DeleteCommunity,
RemoveCommunity, RemoveCommunity,
UserViewSafe, PersonViewSafe,
AddModToCommunity, AddModToCommunity,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { WebSocketService, UserService } from "../services"; import { WebSocketService, UserService } from "../services";
import { mdToHtml, getUnixTime, wsClient, authField } from "../utils"; import { mdToHtml, getUnixTime, wsClient, authField } from "../utils";
import { CommunityForm } from "./community-form"; import { CommunityForm } from "./community-form";
import { UserListing } from "./user-listing"; import { PersonListing } from "./person-listing";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
import { BannerIconHeader } from "./banner-icon-header"; import { BannerIconHeader } from "./banner-icon-header";
import { Icon } from "./icon"; import { Icon } from "./icon";
@ -21,7 +21,7 @@ import { i18n } from "../i18next";
interface SidebarProps { interface SidebarProps {
community_view: CommunityView; community_view: CommunityView;
moderators: CommunityModeratorView[]; moderators: CommunityModeratorView[];
admins: UserViewSafe[]; admins: PersonViewSafe[];
online: number; online: number;
enableNsfw: boolean; enableNsfw: boolean;
showIcon?: boolean; showIcon?: boolean;
@ -224,7 +224,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<li class="list-inline-item">{i18n.t("mods")}: </li> <li class="list-inline-item">{i18n.t("mods")}: </li>
{this.props.moderators.map(mod => ( {this.props.moderators.map(mod => (
<li class="list-inline-item"> <li class="list-inline-item">
<UserListing user={mod.moderator} /> <PersonListing person={mod.moderator} />
</li> </li>
))} ))}
</ul> </ul>
@ -453,7 +453,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
handleLeaveModTeamClick(i: Sidebar) { handleLeaveModTeamClick(i: Sidebar) {
let form: AddModToCommunity = { let form: AddModToCommunity = {
user_id: UserService.Instance.user.id, person_id: UserService.Instance.localUserView.person.id,
community_id: i.props.community_view.community.id, community_id: i.props.community_view.community.id,
added: false, added: false,
auth: authField(), auth: authField(),
@ -489,24 +489,27 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
} }
private get amCreator(): boolean { private get amCreator(): boolean {
return this.props.community_view.creator.id == UserService.Instance.user.id; return (
this.props.community_view.creator.id ==
UserService.Instance.localUserView.person.id
);
} }
get canMod(): boolean { get canMod(): boolean {
return ( return (
UserService.Instance.user && UserService.Instance.localUserView &&
this.props.moderators this.props.moderators
.map(m => m.moderator.id) .map(m => m.moderator.id)
.includes(UserService.Instance.user.id) .includes(UserService.Instance.localUserView.person.id)
); );
} }
get canAdmin(): boolean { get canAdmin(): boolean {
return ( return (
UserService.Instance.user && UserService.Instance.localUserView &&
this.props.admins this.props.admins
.map(a => a.user.id) .map(a => a.person.id)
.includes(UserService.Instance.user.id) .includes(UserService.Instance.localUserView.person.id)
); );
} }

View file

@ -1,23 +1,23 @@
import { UserSafeSettings } from "lemmy-js-client"; import { LocalUserSettingsView } from "lemmy-js-client";
import { Helmet } from "inferno-helmet"; import { Helmet } from "inferno-helmet";
import { Component } from "inferno"; import { Component } from "inferno";
interface Props { interface Props {
user: UserSafeSettings | undefined; localUserView: LocalUserSettingsView | undefined;
} }
export class Theme extends Component<Props> { export class Theme extends Component<Props> {
render() { render() {
const { user } = this.props; let user = this.props.localUserView;
const hasUserTheme = user && user.theme !== "browser"; let hasTheme = user && user.local_user.theme !== "browser";
return ( return (
<Helmet> <Helmet>
{hasUserTheme ? ( {hasTheme ? (
<link <link
rel="stylesheet" rel="stylesheet"
type="text/css" type="text/css"
href={`/static/assets/css/themes/${user.theme}.min.css`} href={`/static/assets/css/themes/${user.local_user.theme}.min.css`}
/> />
) : ( ) : (
[ [

View file

@ -4,6 +4,6 @@ import { i18n } from "./i18next";
import { getLanguage } from "./utils"; import { getLanguage } from "./utils";
export function initializeSite(site: GetSiteResponse) { export function initializeSite(site: GetSiteResponse) {
UserService.Instance.user = site.my_user; UserService.Instance.localUserView = site.my_user;
i18n.changeLanguage(getLanguage()); i18n.changeLanguage(getLanguage());
} }

View file

@ -2,7 +2,7 @@ import {
CommentView, CommentView,
GetSiteResponse, GetSiteResponse,
LemmyHttp, LemmyHttp,
UserMentionView, PersonMentionView,
} from "lemmy-js-client"; } from "lemmy-js-client";
export interface IsoData { export interface IsoData {
@ -32,7 +32,7 @@ export interface InitialFetchRequest {
} }
export interface CommentNode { export interface CommentNode {
comment_view: CommentView | UserMentionView; comment_view: CommentView | PersonMentionView;
children?: CommentNode[]; children?: CommentNode[];
depth?: number; depth?: number;
} }
@ -67,7 +67,7 @@ export enum BanType {
Site, Site,
} }
export enum UserDetailsView { export enum PersonDetailsView {
Overview, Overview,
Comments, Comments,
Posts, Posts,

View file

@ -8,7 +8,7 @@ import { PasswordChange } from "./components/password_change";
import { Post } from "./components/post"; import { Post } from "./components/post";
import { Community } from "./components/community"; import { Community } from "./components/community";
import { Communities } from "./components/communities"; import { Communities } from "./components/communities";
import { User } from "./components/user"; import { Person } from "./components/person";
import { Modlog } from "./components/modlog"; import { Modlog } from "./components/modlog";
import { Setup } from "./components/setup"; import { Setup } from "./components/setup";
import { AdminSettings } from "./components/admin-settings"; import { AdminSettings } from "./components/admin-settings";
@ -93,23 +93,23 @@ export const routes: IRoutePropsWithFetch[] = [
}, },
{ {
path: `/u/:username/view/:view/sort/:sort/page/:page`, path: `/u/:username/view/:view/sort/:sort/page/:page`,
component: User, component: Person,
fetchInitialData: req => User.fetchInitialData(req), fetchInitialData: req => Person.fetchInitialData(req),
}, },
{ {
path: `/user/:id/view/:view/sort/:sort/page/:page`, path: `/user/:id/view/:view/sort/:sort/page/:page`,
component: User, component: Person,
fetchInitialData: req => User.fetchInitialData(req), fetchInitialData: req => Person.fetchInitialData(req),
}, },
{ {
path: `/user/:id`, path: `/user/:id`,
component: User, component: Person,
fetchInitialData: req => User.fetchInitialData(req), fetchInitialData: req => Person.fetchInitialData(req),
}, },
{ {
path: `/u/:username`, path: `/u/:username`,
component: User, component: Person,
fetchInitialData: req => User.fetchInitialData(req), fetchInitialData: req => Person.fetchInitialData(req),
}, },
{ {
path: `/inbox`, path: `/inbox`,

View file

@ -1,17 +1,18 @@
// import Cookies from 'js-cookie'; // import Cookies from 'js-cookie';
import IsomorphicCookie from "isomorphic-cookie"; import IsomorphicCookie from "isomorphic-cookie";
import { UserSafeSettings, LoginResponse } from "lemmy-js-client"; import { LocalUserSettingsView, LoginResponse } from "lemmy-js-client";
import jwt_decode from "jwt-decode"; import jwt_decode from "jwt-decode";
import { Subject, BehaviorSubject } from "rxjs"; import { Subject, BehaviorSubject } from "rxjs";
interface Claims { interface Claims {
id: number; sub: number;
iss: string; iss: string;
iat: number;
} }
export class UserService { export class UserService {
private static _instance: UserService; private static _instance: UserService;
public user: UserSafeSettings; public localUserView: LocalUserSettingsView;
public claims: Claims; public claims: Claims;
public jwtSub: Subject<string> = new Subject<string>(); public jwtSub: Subject<string> = new Subject<string>();
public unreadCountSub: BehaviorSubject<number> = new BehaviorSubject<number>( public unreadCountSub: BehaviorSubject<number> = new BehaviorSubject<number>(
@ -38,7 +39,7 @@ export class UserService {
public logout() { public logout() {
IsomorphicCookie.remove("jwt", { secure: false }); IsomorphicCookie.remove("jwt", { secure: false });
this.claims = undefined; this.claims = undefined;
this.user = undefined; this.localUserView = undefined;
// setTheme(); // setTheme();
this.jwtSub.next(); this.jwtSub.next();
console.log("Logged out."); console.log("Logged out.");

View file

@ -1,5 +1,5 @@
import { wsUri } from "../env"; import { wsUri } from "../env";
import { UserViewSafe, WebSocketJsonResponse } from "lemmy-js-client"; import { PersonViewSafe, WebSocketJsonResponse } from "lemmy-js-client";
import { isBrowser } from "../utils"; import { isBrowser } from "../utils";
import { Observable } from "rxjs"; import { Observable } from "rxjs";
import { share } from "rxjs/operators"; import { share } from "rxjs/operators";
@ -17,8 +17,8 @@ export class WebSocketService {
}; };
public subject: Observable<any>; public subject: Observable<any>;
public admins: UserViewSafe[]; public admins: PersonViewSafe[];
public banned: UserViewSafe[]; public banned: PersonViewSafe[];
private constructor() { private constructor() {
this.ws = new ReconnectingWebSocket(wsUri, [], this.wsOptions); this.ws = new ReconnectingWebSocket(wsUri, [], this.wsOptions);

View file

@ -32,7 +32,7 @@ import "moment/locale/hr";
import { import {
UserOperation, UserOperation,
CommentView, CommentView,
UserSafeSettings, LocalUserSettingsView,
SortType, SortType,
ListingType, ListingType,
SearchType, SearchType,
@ -43,7 +43,7 @@ import {
PostView, PostView,
PrivateMessageView, PrivateMessageView,
LemmyWebsocket, LemmyWebsocket,
UserViewSafe, PersonViewSafe,
CommunityView, CommunityView,
} from "lemmy-js-client"; } from "lemmy-js-client";
@ -78,7 +78,7 @@ export const favIconPngUrl = "/static/assets/apple-touch-icon.png";
// export const defaultFavIcon = `${window.location.protocol}//${window.location.host}${favIconPngUrl}`; // export const defaultFavIcon = `${window.location.protocol}//${window.location.host}${favIconPngUrl}`;
export const repoUrl = "https://github.com/LemmyNet"; export const repoUrl = "https://github.com/LemmyNet";
export const joinLemmyUrl = "https://join.lemmy.ml"; export const joinLemmyUrl = "https://join.lemmy.ml";
export const supportLemmyUrl = "https://join.lemmy.ml/sponsors"; export const supportLemmyUrl = "https://join.lemmy.ml/support";
export const docsUrl = "https://join.lemmy.ml/docs/en/index.html"; export const docsUrl = "https://join.lemmy.ml/docs/en/index.html";
export const helpGuideUrl = "https://join.lemmy.ml/docs/en/about/guide.html"; // TODO find a way to redirect to the non-en folder export const helpGuideUrl = "https://join.lemmy.ml/docs/en/about/guide.html"; // TODO find a way to redirect to the non-en folder
export const markdownHelpUrl = `${helpGuideUrl}#markdown-guide`; export const markdownHelpUrl = `${helpGuideUrl}#markdown-guide`;
@ -91,39 +91,39 @@ export const fetchLimit = 20;
export const mentionDropdownFetchLimit = 10; export const mentionDropdownFetchLimit = 10;
export const languages = [ export const languages = [
{ code: "ca", name: "Català" }, { code: "ca" },
{ code: "en", name: "English" }, { code: "en" },
{ code: "el", name: "Ελληνικά" }, { code: "el" },
{ code: "eu", name: "Euskara" }, { code: "eu" },
{ code: "eo", name: "Esperanto" }, { code: "eo" },
{ code: "es", name: "Español" }, { code: "es" },
{ code: "da", name: "Dansk" }, { code: "da" },
{ code: "de", name: "Deutsch" }, { code: "de" },
{ code: "ga", name: "Gaeilge" }, { code: "ga" },
{ code: "gl", name: "Galego" }, { code: "gl" },
{ code: "hr", name: "hrvatski" }, { code: "hr" },
{ code: "hu", name: "Magyar Nyelv" }, { code: "hu" },
{ code: "ka", name: "ქართული ენა" }, { code: "ka" },
{ code: "ko", name: "한국어" }, { code: "ko" },
{ code: "km", name: "ភាសាខ្មែរ" }, { code: "km" },
{ code: "hi", name: "मानक हिन्दी" }, { code: "hi" },
{ code: "fa", name: "فارسی" }, { code: "fa" },
{ code: "ja", name: "日本語" }, { code: "ja" },
{ code: "oc", name: "Occitan" }, { code: "oc" },
{ code: "pl", name: "Polski" }, { code: "pl" },
{ code: "pt_BR", name: "Português Brasileiro" }, { code: "pt_BR" },
{ code: "zh", name: "中文" }, { code: "zh" },
{ code: "fi", name: "Suomi" }, { code: "fi" },
{ code: "fr", name: "Français" }, { code: "fr" },
{ code: "sv", name: "Svenska" }, { code: "sv" },
{ code: "sq", name: "Shqip" }, { code: "sq" },
{ code: "sr_Latn", name: "srpski" }, { code: "sr_Latn" },
{ code: "th", name: "ภาษาไทย" }, { code: "th" },
{ code: "tr", name: "Türkçe" }, { code: "tr" },
{ code: "uk", name: "Українська Mова" }, { code: "uk" },
{ code: "ru", name: "Русский" }, { code: "ru" },
{ code: "nl", name: "Nederlands" }, { code: "nl" },
{ code: "it", name: "Italiano" }, { code: "it" },
]; ];
export const themes = [ export const themes = [
@ -239,14 +239,14 @@ export function getUnixTime(text: string): number {
} }
export function canMod( export function canMod(
user: UserSafeSettings, localUserView: LocalUserSettingsView,
modIds: number[], modIds: number[],
creator_id: number, creator_id: number,
onSelf = false onSelf = false
): boolean { ): boolean {
// You can do moderator actions only on the mods added after you. // You can do moderator actions only on the mods added after you.
if (user) { if (localUserView) {
let yourIndex = modIds.findIndex(id => id == user.id); let yourIndex = modIds.findIndex(id => id == localUserView.person.id);
if (yourIndex == -1) { if (yourIndex == -1) {
return false; return false;
} else { } else {
@ -367,8 +367,12 @@ export function debounce(func: any, wait = 1000, immediate = false) {
// TODO // TODO
export function getLanguage(override?: string): string { export function getLanguage(override?: string): string {
let user = UserService.Instance.user; let localUserView = UserService.Instance.localUserView;
let lang = override || (user && user.lang ? user.lang : "browser"); let lang =
override ||
(localUserView?.local_user.lang
? localUserView.local_user.lang
: "browser");
if (lang == "browser" && isBrowser()) { if (lang == "browser" && isBrowser()) {
return getBrowserLanguage(); return getBrowserLanguage();
@ -377,7 +381,6 @@ export function getLanguage(override?: string): string {
} }
} }
// TODO
export function getBrowserLanguage(): string { export function getBrowserLanguage(): string {
return navigator.language; return navigator.language;
} }
@ -508,21 +511,21 @@ export function objectFlip(obj: any) {
export function showAvatars(): boolean { export function showAvatars(): boolean {
return ( return (
(UserService.Instance.user && UserService.Instance.user.show_avatars) || UserService.Instance.localUserView?.local_user.show_avatars ||
!UserService.Instance.user !UserService.Instance.localUserView
); );
} }
export function isCakeDay(published: string): boolean { export function isCakeDay(published: string): boolean {
// moment(undefined) or moment.utc(undefined) returns the current date/time // moment(undefined) or moment.utc(undefined) returns the current date/time
// moment(null) or moment.utc(null) returns null // moment(null) or moment.utc(null) returns null
const userCreationDate = moment.utc(published || null).local(); const createDate = moment.utc(published || null).local();
const currentDate = moment(new Date()); const currentDate = moment(new Date());
return ( return (
userCreationDate.date() === currentDate.date() && createDate.date() === currentDate.date() &&
userCreationDate.month() === currentDate.month() && createDate.month() === currentDate.month() &&
userCreationDate.year() !== currentDate.year() createDate.year() !== currentDate.year()
); );
} }
@ -666,15 +669,15 @@ export function setupTribute() {
// menuItemLimit: mentionDropdownFetchLimit, // menuItemLimit: mentionDropdownFetchLimit,
menuShowMinLength: 2, menuShowMinLength: 2,
}, },
// Users // Persons
{ {
trigger: "@", trigger: "@",
selectTemplate: (item: any) => { selectTemplate: (item: any) => {
let it: UserTribute = item.original; let it: PersonTribute = item.original;
return `[${it.key}](${it.view.user.actor_id})`; return `[${it.key}](${it.view.person.actor_id})`;
}, },
values: (text: string, cb: (users: UserTribute[]) => any) => { values: (text: string, cb: (persons: PersonTribute[]) => any) => {
userSearch(text, (users: UserTribute[]) => cb(users)); personSearch(text, (persons: PersonTribute[]) => cb(persons));
}, },
allowSpaces: false, allowSpaces: false,
autocompleteMode: true, autocompleteMode: true,
@ -721,12 +724,12 @@ export function setupTippy() {
} }
} }
interface UserTribute { interface PersonTribute {
key: string; key: string;
view: UserViewSafe; view: PersonViewSafe;
} }
function userSearch(text: string, cb: (users: UserTribute[]) => any) { function personSearch(text: string, cb: (persons: PersonTribute[]) => any) {
if (text) { if (text) {
let form: Search = { let form: Search = {
q: text, q: text,
@ -739,20 +742,20 @@ function userSearch(text: string, cb: (users: UserTribute[]) => any) {
WebSocketService.Instance.send(wsClient.search(form)); WebSocketService.Instance.send(wsClient.search(form));
let userSub = WebSocketService.Instance.subject.subscribe( let personSub = WebSocketService.Instance.subject.subscribe(
msg => { msg => {
let res = wsJsonToRes(msg); let res = wsJsonToRes(msg);
if (res.op == UserOperation.Search) { if (res.op == UserOperation.Search) {
let data = res.data as SearchResponse; let data = res.data as SearchResponse;
let users: UserTribute[] = data.users.map(uv => { let persons: PersonTribute[] = data.users.map(pv => {
let tribute: UserTribute = { let tribute: PersonTribute = {
key: `@${uv.user.name}@${hostname(uv.user.actor_id)}`, key: `@${pv.person.name}@${hostname(pv.person.actor_id)}`,
view: uv, view: pv,
}; };
return tribute; return tribute;
}); });
cb(users); cb(persons);
userSub.unsubscribe(); personSub.unsubscribe();
} }
}, },
err => console.error(err), err => console.error(err),
@ -811,8 +814,10 @@ function communitySearch(
export function getListingTypeFromProps(props: any): ListingType { export function getListingTypeFromProps(props: any): ListingType {
return props.match.params.listing_type return props.match.params.listing_type
? routeListingTypeToEnum(props.match.params.listing_type) ? routeListingTypeToEnum(props.match.params.listing_type)
: UserService.Instance.user : UserService.Instance.localUserView
? Object.values(ListingType)[UserService.Instance.user.default_listing_type] ? Object.values(ListingType)[
UserService.Instance.localUserView.local_user.default_listing_type
]
: ListingType.Local; : ListingType.Local;
} }
@ -826,8 +831,10 @@ export function getDataTypeFromProps(props: any): DataType {
export function getSortTypeFromProps(props: any): SortType { export function getSortTypeFromProps(props: any): SortType {
return props.match.params.sort return props.match.params.sort
? routeSortTypeToEnum(props.match.params.sort) ? routeSortTypeToEnum(props.match.params.sort)
: UserService.Instance.user : UserService.Instance.localUserView
? Object.values(SortType)[UserService.Instance.user.default_sort_type] ? Object.values(SortType)[
UserService.Instance.localUserView.local_user.default_sort_type
]
: SortType.Active; : SortType.Active;
} }

View file

@ -22,6 +22,6 @@
}, },
"include": [ "include": [
"src/**/*", "src/**/*",
"node_modules/inferno/dist/index.d.ts", "node_modules/inferno/dist/index.d.ts"
] ]
} }

View file

@ -4833,6 +4833,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
iso-639-1@^2.1.9:
version "2.1.9"
resolved "https://registry.yarnpkg.com/iso-639-1/-/iso-639-1-2.1.9.tgz#e41b11d4f1808e5316d0252c3fa16eeb9b37bb58"
integrity sha512-owRu9up+Cpx/hwSzm83j6G8PtC7U99UCtPVItsafefNfEgMl+pi8KBwhXwJkJfp6IouyYWFxj8n24SvCWpKZEQ==
isobject@^2.0.0: isobject@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
@ -5022,10 +5027,10 @@ lcid@^1.0.0:
dependencies: dependencies:
invert-kv "^1.0.0" invert-kv "^1.0.0"
lemmy-js-client@0.10.0-rc.1: lemmy-js-client@0.10.0-rc.10:
version "0.10.0-rc.1" version "0.10.0-rc.10"
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.10.0-rc.1.tgz#4a9b9db8fcc8229d634920d7e66f63ab5db8b28e" resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.10.0-rc.10.tgz#36802f64191a10e8e70624e04d0cc98de465ae5a"
integrity sha512-18TQO+EpE+mgCWSwynfFvDCASUjzTkr73/CbneMMHcqexq2R4donE+pNDFFSDHOeYIbdna0f4GZEJhyeh6826g== integrity sha512-WOAjHE0SgNbpq7pA56F3zJUI7pNdtdpdE/KViAjgfEHGW+yscu/nhLzYf/QA1QjI0ONeZc9U254xOnXzSs8XUw==
levn@^0.4.1: levn@^0.4.1:
version "0.4.1" version "0.4.1"