Merge branch 'main' into more-inbox-permissions

This commit is contained in:
dessalines 2020-08-04 14:39:24 +00:00
commit 3db2536a1f
22 changed files with 109 additions and 52 deletions

2
ansible/VERSION vendored
View File

@ -1 +1 @@
v0.7.35
v0.7.39

View File

@ -60,6 +60,9 @@ server {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;

View File

@ -17,6 +17,9 @@ http {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
@ -57,6 +60,9 @@ http {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
@ -97,6 +103,9 @@ http {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Cuts off the trailing slash on URLs to make them valid
rewrite ^(.+)/+$ $1 permanent;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;

View File

@ -12,7 +12,7 @@ services:
restart: always
lemmy:
image: dessalines/lemmy:v0.7.35
image: dessalines/lemmy:v0.7.39
ports:
- "127.0.0.1:8536:8536"
restart: always

View File

@ -1,5 +1,5 @@
#!/bin/sh
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
docker tag dessalines/lemmy:travis \
dessalines/lemmy:v0.7.35
docker push dessalines/lemmy:v0.7.35
dessalines/lemmy:v0.7.39
docker push dessalines/lemmy:v0.7.39

View File

@ -1,7 +1,7 @@
### Install build requirements
#### Ubuntu
```
sudo apt install git cargo libssl-dev pkg-config libpq-dev yarn curl gnupg2
sudo apt install git cargo libssl-dev pkg-config libpq-dev yarn curl gnupg2 espeak
# install yarn
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

View File

@ -1 +1 @@
pub const VERSION: &str = "v0.7.35";
pub const VERSION: &str = "v0.7.39";

View File

@ -87,6 +87,10 @@
line-height: 1.0;
}
.post-title a:visited {
color: var(--gray) !important;
}
.icon {
display: inline-flex;
width: 1em;

View File

@ -144,6 +144,9 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
// This only finishes this form, if the randomly generated form_id matches the one received
if (this.state.commentForm.form_id == data.form_id) {
this.setState({ finished: true });
// Necessary because it broke tribute for some reaso
this.setState({ finished: false });
}
}
}

View File

@ -275,21 +275,21 @@ export class Inbox extends Component<any, InboxState> {
);
}
combined(): Array<ReplyType> {
return [
...this.state.replies,
...this.state.mentions,
...this.state.messages,
].sort((a, b) => b.published.localeCompare(a.published));
}
all() {
let combined: Array<ReplyType> = [];
combined.push(...this.state.replies);
combined.push(...this.state.mentions);
combined.push(...this.state.messages);
// Sort it
combined.sort((a, b) => b.published.localeCompare(a.published));
return (
<div>
{combined.map(i =>
{this.combined().map(i =>
isCommentType(i) ? (
<CommentNodes
key={i.id}
nodes={[{ comment: i }]}
noIndent
markable
@ -298,7 +298,7 @@ export class Inbox extends Component<any, InboxState> {
enableDownvotes={this.state.site.enable_downvotes}
/>
) : (
<PrivateMessage privateMessage={i} />
<PrivateMessage key={i.id} privateMessage={i} />
)
)}
</div>
@ -325,6 +325,7 @@ export class Inbox extends Component<any, InboxState> {
<div>
{this.state.mentions.map(mention => (
<CommentNodes
key={mention.id}
nodes={[{ comment: mention }]}
noIndent
markable
@ -341,7 +342,7 @@ export class Inbox extends Component<any, InboxState> {
return (
<div>
{this.state.messages.map(message => (
<PrivateMessage privateMessage={message} />
<PrivateMessage key={message.id} privateMessage={message} />
))}
</div>
);
@ -565,7 +566,6 @@ export class Inbox extends Component<any, InboxState> {
} else if (data.comment.creator_id == UserService.Instance.user.id) {
toast(i18n.t('reply_sent'));
}
this.setState(this.state);
} else if (res.op == UserOperation.CreatePrivateMessage) {
let data = res.data as PrivateMessageResponse;
if (data.message.recipient_id == UserService.Instance.user.id) {
@ -597,7 +597,10 @@ export class Inbox extends Component<any, InboxState> {
this.state.replies.filter(r => !r.read).length +
this.state.mentions.filter(r => !r.read).length +
this.state.messages.filter(
r => !r.read && r.creator_id !== UserService.Instance.user.id
r =>
UserService.Instance.user &&
!r.read &&
r.creator_id !== UserService.Instance.user.id
).length
);
}

View File

@ -25,6 +25,7 @@ interface MarkdownTextAreaProps {
onSubmit?(msg: { val: string; formId: string }): any;
onContentChange?(val: string): any;
onReplyCancel?(): any;
hideNavigationWarnings?: boolean;
}
interface MarkdownTextAreaState {
@ -78,7 +79,7 @@ export class MarkdownTextArea extends Component<
}
componentDidUpdate() {
if (this.state.content) {
if (!this.props.hideNavigationWarnings && this.state.content) {
window.onbeforeunload = () => true;
} else {
window.onbeforeunload = undefined;
@ -110,7 +111,10 @@ export class MarkdownTextArea extends Component<
render() {
return (
<form id={this.formId} onSubmit={linkEvent(this, this.handleSubmit)}>
<Prompt when={this.state.content} message={i18n.t('block_leaving')} />
<Prompt
when={!this.props.hideNavigationWarnings && this.state.content}
message={i18n.t('block_leaving')}
/>
<div class="form-group row">
<div className={`col-sm-12`}>
<textarea

View File

@ -431,6 +431,7 @@ export class Navbar extends Component<any, NavbarState> {
// The login
if (data.my_user) {
UserService.Instance.user = data.my_user;
WebSocketService.Instance.userJoin();
// On the first load, check the unreads
if (this.state.isLoggedIn == false) {
this.requestNotificationPermission();

View File

@ -315,7 +315,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<h5 className="mb-1 d-inline-block">
{this.props.showBody && post.url ? (
<a
className="text-body"
className={!post.stickied ? 'text-body' : 'text-primary'}
href={post.url}
target="_blank"
title={post.url}
@ -325,7 +325,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</a>
) : (
<Link
className="text-body"
className={!post.stickied ? 'text-body' : 'text-primary'}
to={`/post/${post.id}`}
title={i18n.t('comments')}
>
@ -419,7 +419,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('stickied')}
>
<svg class={`icon icon-inline text-success`}>
<svg class={`icon icon-inline text-primary`}>
<use xlinkHref="#icon-pin"></use>
</svg>
</small>

View File

@ -45,7 +45,10 @@ export class PrivateMessage extends Component<
}
get mine(): boolean {
return UserService.Instance.user.id == this.props.privateMessage.creator_id;
return (
UserService.Instance.user &&
UserService.Instance.user.id == this.props.privateMessage.creator_id
);
}
render() {
@ -113,6 +116,7 @@ export class PrivateMessage extends Component<
<PrivateMessageForm
privateMessage={message}
onEdit={this.handlePrivateMessageEdit}
onCreate={this.handlePrivateMessageCreate}
onCancel={this.handleReplyCancel}
/>
)}
@ -280,9 +284,14 @@ export class PrivateMessage extends Component<
this.setState(this.state);
}
handlePrivateMessageCreate() {
this.state.showReply = false;
this.setState(this.state);
toast(i18n.t('message_sent'));
handlePrivateMessageCreate(message: PrivateMessageI) {
if (
UserService.Instance.user &&
message.creator_id == UserService.Instance.user.id
) {
this.state.showReply = false;
this.setState(this.state);
toast(i18n.t('message_sent'));
}
}
}

View File

@ -289,6 +289,7 @@ export class Search extends Component<any, SearchState> {
<div class="col-12">
{i.type_ == 'posts' && (
<PostListing
key={(i.data as Post).id}
post={i.data as Post}
showCommunity
enableDownvotes={this.state.site.enable_downvotes}
@ -297,6 +298,7 @@ export class Search extends Component<any, SearchState> {
)}
{i.type_ == 'comments' && (
<CommentNodes
key={(i.data as Comment).id}
nodes={[{ comment: i.data as Comment }]}
locked
noIndent

View File

@ -111,6 +111,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
<MarkdownTextArea
initialContent={this.state.siteForm.description}
onContentChange={this.handleSiteDescriptionChange}
hideNavigationWarnings
/>
</div>
</div>

View File

@ -65,6 +65,6 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
}
handleSortChange(i: SortSelect, event: any) {
i.props.onChange(event.target.value);
i.props.onChange(Number(event.target.value));
}
}

View File

@ -150,6 +150,7 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
<div>
{i.type === 'posts' ? (
<PostListing
key={(i.data as Post).id}
post={i.data as Post}
admins={this.props.admins}
showCommunity
@ -158,6 +159,7 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
/>
) : (
<CommentNodes
key={(i.data as Comment).id}
nodes={[{ comment: i.data as Comment }]}
admins={this.props.admins}
noBorder

View File

@ -152,9 +152,6 @@ export class User extends Component<any, UserState> {
this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
this
);
this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
this
);
this.handlePageChange = this.handlePageChange.bind(this);
this.handleUserSettingsBioChange = this.handleUserSettingsBioChange.bind(
this
@ -384,12 +381,14 @@ export class User extends Component<any, UserState> {
)}
</ul>
</h5>
<div className="d-flex align-items-center mb-2">
<div
className="md-div"
dangerouslySetInnerHTML={mdToHtml(user.bio)}
/>
</div>
{user.bio && (
<div className="d-flex align-items-center mb-2">
<div
className="md-div"
dangerouslySetInnerHTML={mdToHtml(user.bio)}
/>
</div>
)}
<div className="d-flex align-items-center mb-2">
<svg class="icon">
<use xlinkHref="#icon-cake"></use>
@ -594,6 +593,7 @@ export class User extends Component<any, UserState> {
initialContent={this.state.userSettingsForm.bio}
onContentChange={this.handleUserSettingsBioChange}
maxLength={300}
hideNavigationWarnings
/>
</div>
</div>

View File

@ -82,10 +82,6 @@ export class WebSocketService {
this.ws.onopen = () => {
console.log(`Connected to ${wsUri}`);
if (UserService.Instance.user) {
this.userJoin();
}
if (!firstConnect) {
let res: WebSocketJsonResponse = {
reconnect: true,

11
ui/src/utils.ts vendored
View File

@ -588,6 +588,9 @@ export function messageToastify(
export function setupTribute(): Tribute {
return new Tribute({
noMatchTemplate: function () {
return '';
},
collection: [
// Emojis
{
@ -669,7 +672,7 @@ function userSearch(text: string, cb: any) {
WebSocketService.Instance.search(form);
this.userSub = WebSocketService.Instance.subject.subscribe(
let userSub = WebSocketService.Instance.subject.subscribe(
msg => {
let res = wsJsonToRes(msg);
if (res.op == UserOperation.Search) {
@ -683,7 +686,7 @@ function userSearch(text: string, cb: any) {
};
});
cb(users);
this.userSub.unsubscribe();
userSub.unsubscribe();
}
},
err => console.error(err),
@ -706,7 +709,7 @@ function communitySearch(text: string, cb: any) {
WebSocketService.Instance.search(form);
this.communitySub = WebSocketService.Instance.subject.subscribe(
let communitySub = WebSocketService.Instance.subject.subscribe(
msg => {
let res = wsJsonToRes(msg);
if (res.op == UserOperation.Search) {
@ -720,7 +723,7 @@ function communitySearch(text: string, cb: any) {
};
});
cb(communities);
this.communitySub.unsubscribe();
communitySub.unsubscribe();
}
},
err => console.error(err),

View File

@ -14,7 +14,7 @@
"number_of_comments": "{{count}} Kommentar",
"number_of_comments_plural": "{{count}} Kommentare",
"remove_comment": "Kommentar löschen",
"communities": "Communitys",
"communities": "Communities",
"users": "Benutzer",
"create_a_community": "Eine Community anlegen",
"create_community": "Community erstellen",
@ -168,7 +168,7 @@
"yes": "Ja",
"no": "Nein",
"powered_by": "Bereitgestellt durch",
"landing_0": "Lemmy ist ein <1>Link-Aggregator</1> / Reddit Alternative im <2>Fediverse</2>.<3></3>Es ist selbst-hostbar, hat live-updates von Kommentar-threads und ist winzig (<4>~80kB</4>). Federation in das ActivityPub Netzwerk ist geplant. <5></5>Dies ist eine <6>sehr frühe Beta Version</6>, und viele Features funktionieren zurzeit nicht richtig oder fehlen. <7></7>Schlage neue Features vor oder melde Bugs <8>hier.</8><9></9>Gebaut mit <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>.",
"landing": "Lemmy ist ein <1>Link-Aggregator</1> / Reddit Alternative im <2>Fediverse</2>.<3></3>Es ist selbst-hostbar, hat live-updates von Kommentar-threads und ist winzig (<4>~80kB</4>). Federation in das ActivityPub Netzwerk ist geplant. <5></5>Dies ist eine <6>sehr frühe Beta Version</6>, und viele Features funktionieren zurzeit nicht richtig oder fehlen. <7></7>Schlage neue Features vor oder melde Bugs <8>hier.</8><9></9>Gebaut mit <10>Rust</10>, <11>Actix</11>, <12>Inferno</12>, <13>Typescript</13>. <14></14> <15>Vielen Dank an unsere Mitwirkenden: </15> dessalines, Nutomic, asonix, zacanger, and iav.",
"not_logged_in": "Nicht eingeloggt.",
"community_ban": "Du wurdest von dieser Community gebannt.",
"site_ban": "Du wurdest von dieser Seite gebannt",
@ -216,7 +216,7 @@
"messages": "Nachrichten",
"old_password": "Letztes Passwort",
"matrix_user_id": "Matrix Benutzer",
"private_message_disclaimer": "Achtung: Private Nachrichten sind in Lemmy nicht sicher. Bitte erstelle einen <1>Riot.im</1> Account für sicheren Nachrichtenverkehr.",
"private_message_disclaimer": "Achtung: Private Nachrichten sind in Lemmy nicht verschlüsselt. Bitte erstelle einen<1>Element.io</1> Account für sicheren Nachrichtenverkehr.",
"send_notifications_to_email": "Sende Benachrichtigungen per Email",
"downvotes_disabled": "Downvotes deaktiviert",
"enable_downvotes": "Aktiviere Downvotes",
@ -256,5 +256,22 @@
"click_to_delete_picture": "Klicke, um das Bild zu löschen.",
"picture_deleted": "Bild gelöscht.",
"select_a_community": "Wähle eine Community aus",
"invalid_username": "Ungültiger Benutzername."
"invalid_username": "Ungültiger Benutzername.",
"bold": "fett",
"italic": "kursiv",
"subscript": "Tiefzeichen",
"superscript": "Hochzeichen",
"header": "Header",
"strikethrough": "durchgestrichen",
"quote": "Zitat",
"spoiler": "Spoiler",
"list": "Liste",
"not_a_moderator": "Kein Moderator.",
"invalid_url": "Ungültige URL.",
"must_login": "Du musst <1>eingeloggt oder registriert</1> sein um zu Kommentieren.",
"no_password_reset": "Du kannst dein Passwort ohne E-Mail nicht zurücksetzen.",
"cake_day_info": "Heute ist {{ creator_name }}'s cake day!",
"invalid_post_title": "Ungültiger Post Titel",
"cake_day_title": "Cake day:",
"what_is": "Was ist"
}