From 41d1af6fd59620c537fa52eafd33a2d9f282346f Mon Sep 17 00:00:00 2001 From: xyvs Date: Thu, 17 Oct 2019 16:49:39 -0500 Subject: [PATCH 001/381] Spanish translations (#303) --- ui/src/translations/es.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui/src/translations/es.ts b/ui/src/translations/es.ts index 3e92a8fb3..ad1f5d1c5 100644 --- a/ui/src/translations/es.ts +++ b/ui/src/translations/es.ts @@ -55,6 +55,8 @@ export const es = { mark_as_unread: 'marcar como no leído', delete: 'eliminar', deleted: 'eliminado', + delete_account: 'Eliminar Cuenta', + delete_account_confirm: 'Peligro: esta acción eliminará permanentemente tu información. ¿Estás seguro?', restore: 'restaurar', ban: 'expulsar', ban_from_site: 'expulsar del sitio', @@ -64,11 +66,13 @@ export const es = { save: 'guardar', unsave: 'descartar', create: 'crear', + creator: 'creador', username: 'Nombre de Usuario', email_or_username: 'Correo electrónico o Nombre de Usuario', number_of_users:'{{count}} Usuarios', number_of_subscribers:'{{count}} Suscriptores', number_of_points:'{{count}} Puntos', + number_online: '{{count}} Usaurios En Línea', name: 'Nombre', title: 'Titulo', category: 'Categoría', @@ -127,6 +131,7 @@ export const es = { modified: 'modificado', nsfw: 'NSFW', show_nsfw: 'Mostrar contenido NSFW', + theme: 'Tema', sponsors: 'Patrocinadores', sponsors_of_lemmy: 'Patrocinadores de Lemmy', sponsor_message: 'Lemmy es software libre y de <1>código abierto, lo que significa que no tendrá publicidades, monetización, ni capitales emprendedores, nunca. Tus donaciones apoyan directamente el desarrollo a tiempo completo del proyecto. Muchas gracias a las siguientes personas:', From 5ae00abb2ad91d0ad5c78dfbff7ecb795ac18de1 Mon Sep 17 00:00:00 2001 From: zacanger Date: Thu, 17 Oct 2019 19:54:01 -0600 Subject: [PATCH 002/381] chore: simplify validUrl fn --- ui/src/utils.ts | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/ui/src/utils.ts b/ui/src/utils.ts index cf2908824..26d4ec7c9 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -75,11 +75,11 @@ export function mdToHtml(text: string) { return {__html: md.render(text)}; } -export function getUnixTime(text: string): number { +export function getUnixTime(text: string): number { return text ? new Date(text).getTime()/1000 : undefined; } -export function addTypeInfo(arr: Array, name: string): Array<{type_: string, data: T}> { +export function addTypeInfo(arr: Array, name: string): Array<{type_: string, data: T}> { return arr.map(e => {return {type_: name, data: e}}); } @@ -89,9 +89,9 @@ export function canMod(user: User, modIds: Array, creator_id: number, on let yourIndex = modIds.findIndex(id => id == user.id); if (yourIndex == -1) { return false; - } else { + } else { // onSelf +1 on mod actions not for yourself, IE ban, remove, etc - modIds = modIds.slice(0, yourIndex+(onSelf ? 0 : 1)); + modIds = modIds.slice(0, yourIndex+(onSelf ? 0 : 1)); return !modIds.includes(creator_id); } } else { @@ -116,13 +116,11 @@ export function isVideo(url: string) { } export function validURL(str: string) { - var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol - '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name - '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address - '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path - '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string - '(\\#[-a-z\\d_]*)?$','i'); // fragment locator - return !!pattern.test(str); + try { + return !!new URL(str); + } catch { + return false; + } } export function capitalizeFirstLetter(str: string): string { @@ -176,9 +174,9 @@ export function debounce(func: any, wait: number = 500, immediate: boolean = fal // and not already in a timeout then the answer is: Yes var callNow = immediate && !timeout; - // This is the basic debounce behaviour where you can call this - // function several times, but it will only execute once - // [before or after imposing a delay]. + // This is the basic debounce behaviour where you can call this + // function several times, but it will only execute once + // [before or after imposing a delay]. // Each time the returned function is called, the timer starts over. clearTimeout(timeout); @@ -192,7 +190,7 @@ export function debounce(func: any, wait: number = 500, immediate: boolean = fal // Check if the function already ran with the immediate flag if (!immediate) { // Call the original function with apply - // apply lets you define the 'this' object as well as the arguments + // apply lets you define the 'this' object as well as the arguments // (both captured before setTimeout) func.apply(context, args); } @@ -249,6 +247,6 @@ export function setTheme(theme: string = 'darkly') { styleSheet.removeAttribute("disabled"); } else { styleSheet.setAttribute("disabled", "disabled"); - } + } } } From 773020ac9d92276c1871d79ea589a947e80e0bce Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 17 Oct 2019 20:19:20 -0700 Subject: [PATCH 003/381] Don't allow image uploads for non-logged-in users. - Fixes #297 --- ui/src/components/comment-form.tsx | 4 ++-- ui/src/components/post-form.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index 7c6460a27..2095e9e5f 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -139,8 +139,8 @@ export class CommentForm extends Component { {this.props.node && } #
- - + +
{this.state.imageLoading && diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index b59d07d6f..09b9606ea 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -112,8 +112,8 @@ export class PostForm extends Component {
#
}
- - + +
{this.state.imageLoading && From 6cfefaac45cde4e50a96f43fc50c492ee8991a76 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 17 Oct 2019 20:20:59 -0700 Subject: [PATCH 004/381] Update translation report. --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 40834e507..4c4020efa 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ This is a **very early beta version**, and a lot of features are currently broke Front Page|Post ---|--- ![main screen](https://i.imgur.com/y64BtXC.png)|![chat screen](https://i.imgur.com/vsOr87q.png) + ## Features - Open source, [AGPL License](/LICENSE). @@ -35,12 +36,12 @@ Front Page|Post - Both site admins, and community moderators, who can appoint other moderators. - Can lock, remove, and restore posts and comments. - Can ban and unban users from communities and the site. + - Can transfer site and communities to others. - Clean, mobile-friendly interface. - i18n / internationalization support. - NSFW post / community support. - Cross-posting support. -- A *similar post search* when creating new posts. -- Can transfer site and communities to others. +- A *similar post search* when creating new posts. Great for question / answer communities. - High performance. - Server is written in rust. - Front end is `~80kB` gzipped. @@ -202,7 +203,7 @@ lang | done | missing --- | --- | --- de | 82% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,settings,stickied,delete_account,delete_account_confirm,banned,creator,number_online,subscribed,expires,recent_comments,nsfw,show_nsfw,theme,crypto,monero,joined,by,to,transfer_community,transfer_site,are_you_sure,yes,no eo | 91% | number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,theme,are_you_sure,yes,no -es | 97% | delete_account,delete_account_confirm,creator,number_online,theme +es | 100% | fr | 95% | view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,creator,number_online,theme nl | 93% | preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,theme ru | 86% | cross_posts,cross_post,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,recent_comments,theme,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no From 26ea18ded78a4c6774050d84b27343f26fd68fe6 Mon Sep 17 00:00:00 2001 From: zacanger Date: Thu, 17 Oct 2019 21:54:29 -0600 Subject: [PATCH 005/381] revert whitespace changes --- ui/src/utils.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ui/src/utils.ts b/ui/src/utils.ts index 26d4ec7c9..350a8205a 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -75,11 +75,11 @@ export function mdToHtml(text: string) { return {__html: md.render(text)}; } -export function getUnixTime(text: string): number { +export function getUnixTime(text: string): number { return text ? new Date(text).getTime()/1000 : undefined; } -export function addTypeInfo(arr: Array, name: string): Array<{type_: string, data: T}> { +export function addTypeInfo(arr: Array, name: string): Array<{type_: string, data: T}> { return arr.map(e => {return {type_: name, data: e}}); } @@ -89,9 +89,9 @@ export function canMod(user: User, modIds: Array, creator_id: number, on let yourIndex = modIds.findIndex(id => id == user.id); if (yourIndex == -1) { return false; - } else { + } else { // onSelf +1 on mod actions not for yourself, IE ban, remove, etc - modIds = modIds.slice(0, yourIndex+(onSelf ? 0 : 1)); + modIds = modIds.slice(0, yourIndex+(onSelf ? 0 : 1)); return !modIds.includes(creator_id); } } else { @@ -174,9 +174,9 @@ export function debounce(func: any, wait: number = 500, immediate: boolean = fal // and not already in a timeout then the answer is: Yes var callNow = immediate && !timeout; - // This is the basic debounce behaviour where you can call this - // function several times, but it will only execute once - // [before or after imposing a delay]. + // This is the basic debounce behaviour where you can call this + // function several times, but it will only execute once + // [before or after imposing a delay]. // Each time the returned function is called, the timer starts over. clearTimeout(timeout); @@ -190,7 +190,7 @@ export function debounce(func: any, wait: number = 500, immediate: boolean = fal // Check if the function already ran with the immediate flag if (!immediate) { // Call the original function with apply - // apply lets you define the 'this' object as well as the arguments + // apply lets you define the 'this' object as well as the arguments // (both captured before setTimeout) func.apply(context, args); } @@ -247,6 +247,6 @@ export function setTheme(theme: string = 'darkly') { styleSheet.removeAttribute("disabled"); } else { styleSheet.setAttribute("disabled", "disabled"); - } + } } } From 69d1301723c991404356679c46b7c206e6aa48d2 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 17 Oct 2019 21:25:23 -0700 Subject: [PATCH 006/381] Make delete account require password. - Fixes #301 --- server/src/api/user.rs | 9 +++++++++ ui/src/components/user.tsx | 22 +++++++++++++++++----- ui/src/interfaces.ts | 4 ++++ ui/src/services/WebSocketService.ts | 5 ++--- ui/src/translations/en.ts | 2 +- 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/server/src/api/user.rs b/server/src/api/user.rs index b0ed5a4bb..2de809055 100644 --- a/server/src/api/user.rs +++ b/server/src/api/user.rs @@ -105,6 +105,7 @@ pub struct GetReplies { #[derive(Serialize, Deserialize)] pub struct DeleteAccount { + password: String, auth: String, } @@ -601,6 +602,14 @@ impl Perform for Oper { let user_id = claims.id; + let user: User_ = User_::read(&conn, user_id)?; + + // Verify the password + let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false); + if !valid { + return Err(APIError::err(&self.op, "password_incorrect"))?; + } + // Comments let comments = CommentView::list( &conn, diff --git a/ui/src/components/user.tsx b/ui/src/components/user.tsx index c53a672a0..88476bc82 100644 --- a/ui/src/components/user.tsx +++ b/ui/src/components/user.tsx @@ -2,7 +2,7 @@ import { Component, linkEvent } from 'inferno'; import { Link } from 'inferno-router'; import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; -import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse, UserSettingsForm, LoginResponse, BanUserResponse, AddAdminResponse } from '../interfaces'; +import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse, UserSettingsForm, LoginResponse, BanUserResponse, AddAdminResponse, DeleteAccountForm } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { msgOp, fetchLimit, routeSortTypeToEnum, capitalizeFirstLetter, themes, setTheme } from '../utils'; import { PostListing } from './post-listing'; @@ -33,6 +33,7 @@ interface UserState { userSettingsLoading: boolean; deleteAccountLoading: boolean; deleteAccountShowConfirm: boolean; + deleteAccountForm: DeleteAccountForm; } export class User extends Component { @@ -69,6 +70,9 @@ export class User extends Component { userSettingsLoading: null, deleteAccountLoading: null, deleteAccountShowConfirm: false, + deleteAccountForm: { + password: null, + } } constructor(props: any, context: any) { @@ -316,9 +320,10 @@ export class User extends Component { {this.state.deleteAccountShowConfirm && <> - - + + + } @@ -453,12 +458,17 @@ export class User extends Component { i.setState(i.state); } + handleDeleteAccountPasswordChange(i: User, event: any) { + i.state.deleteAccountForm.password = event.target.value; + i.setState(i.state); + } + handleDeleteAccount(i: User, event: any) { event.preventDefault(); i.state.deleteAccountLoading = true; i.setState(i.state); - WebSocketService.Instance.deleteAccount(); + WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm); } parseMessage(msg: any) { @@ -466,6 +476,8 @@ export class User extends Component { let op: UserOperation = msgOp(msg); if (msg.error) { alert(i18n.t(msg.error)); + this.state.deleteAccountLoading = false; + this.setState(this.state); return; } else if (op == UserOperation.GetUserDetails) { let res: UserDetailsResponse = msg; diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index 4bd013ce9..e11dee04a 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -600,3 +600,7 @@ export interface SearchResponse { communities: Array; users: Array; } + +export interface DeleteAccountForm { + password: string; +} diff --git a/ui/src/services/WebSocketService.ts b/ui/src/services/WebSocketService.ts index f8838d400..987cbfdf1 100644 --- a/ui/src/services/WebSocketService.ts +++ b/ui/src/services/WebSocketService.ts @@ -1,5 +1,5 @@ import { wsUri } from '../env'; -import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, SavePostForm, CommentForm, SaveCommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, TransferCommunityForm, AddAdminForm, TransferSiteForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm, UserSettingsForm } from '../interfaces'; +import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, SavePostForm, CommentForm, SaveCommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, TransferCommunityForm, AddAdminForm, TransferSiteForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm, UserSettingsForm, DeleteAccountForm } from '../interfaces'; import { webSocket } from 'rxjs/webSocket'; import { Subject } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; @@ -199,8 +199,7 @@ export class WebSocketService { this.subject.next(this.wsSendWrapper(UserOperation.SaveUserSettings, userSettingsForm)); } - public deleteAccount() { - let form = {}; + public deleteAccount(form: DeleteAccountForm) { this.setAuth(form); this.subject.next(this.wsSendWrapper(UserOperation.DeleteAccount, form)); } diff --git a/ui/src/translations/en.ts b/ui/src/translations/en.ts index 7df3d0236..7a23e2099 100644 --- a/ui/src/translations/en.ts +++ b/ui/src/translations/en.ts @@ -56,7 +56,7 @@ export const en = { delete: 'delete', deleted: 'deleted', delete_account: 'Delete Account', - delete_account_confirm: 'Warning: this will permanently delete all your data. Are you sure?', + delete_account_confirm: 'Warning: this will permanently delete all your data. Enter your password to confirm.', restore: 'restore', ban: 'ban', ban_from_site: 'ban from site', From f7b558f043495d398b35ccb1ddc4b0f0b6beb95a Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 17 Oct 2019 21:41:19 -0700 Subject: [PATCH 007/381] Version v0.3.0.2 --- docker/prod/docker-compose.yml | 2 +- ui/src/version.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index 2983965ac..5c431eccd 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -10,7 +10,7 @@ services: volumes: - lemmy_db:/var/lib/postgresql/data lemmy: - image: dessalines/lemmy:v0.3.0.1 + image: dessalines/lemmy:v0.3.0.2 ports: - "127.0.0.1:8536:8536" environment: diff --git a/ui/src/version.ts b/ui/src/version.ts index 3c1f3d723..87b96ac46 100644 --- a/ui/src/version.ts +++ b/ui/src/version.ts @@ -1 +1 @@ -export let version: string = "v0.3.0.1-0-g95bc3ab"; \ No newline at end of file +export let version: string = "v0.3.0.2-0-g9f5a328"; \ No newline at end of file From 22a1efc7901f5d776c8addf5080e71ae61997b7c Mon Sep 17 00:00:00 2001 From: Matteo Guglielmetti Date: Fri, 18 Oct 2019 10:10:26 +0200 Subject: [PATCH 008/381] Italian complete translation --- ui/src/i18next.ts | 4 +- ui/src/translations/it.ts | 189 ++++++++++++++++++++++++++++++++++++++ ui/src/utils.ts | 3 + 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 ui/src/translations/it.ts diff --git a/ui/src/i18next.ts b/ui/src/i18next.ts index 069c820d1..c45270fe8 100644 --- a/ui/src/i18next.ts +++ b/ui/src/i18next.ts @@ -9,6 +9,7 @@ import { sv } from './translations/sv'; import { ru } from './translations/ru'; import { zh } from './translations/zh'; import { nl } from './translations/nl'; +import { it } from './translations/it'; // https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66 // TODO don't forget to add moment locales for new languages. @@ -22,6 +23,7 @@ const resources = { sv, ru, nl, + it, } function format(value: any, format: any, lng: any) { @@ -40,7 +42,7 @@ i18n resources, interpolation: { format: format - + } }); diff --git a/ui/src/translations/it.ts b/ui/src/translations/it.ts new file mode 100644 index 000000000..6c03c1faf --- /dev/null +++ b/ui/src/translations/it.ts @@ -0,0 +1,189 @@ +export const it = { + translation: { + post: 'post', + remove_post: 'Rimuovi Post', + no_posts: 'Nessun Post.', + create_a_post: 'Crea un post', + create_post: 'Crea Post', + number_of_posts: '{{count}} Posts', + posts: 'Posts', + related_posts: 'Questi post potrebbero essere correlati', + cross_posts: 'Questo link è stato postato anche in:', + cross_post: 'cross-post', + comments: 'Commenti', + number_of_comments: '{{count}} Commenti', + remove_comment: 'Rimuovi Commento', + communities: 'Comunità', + users: 'Utenti', + create_a_community: 'Crea una Comunità', + create_community: 'Crea Comunità', + remove_community: 'Rimuovi Comunità', + subscribed_to_communities: 'Iscritto alle <1>comunità', + trending_communities: '<1>Comunità in crescita', + list_of_communities: 'Lista di comunità', + number_of_communities: '{{count}} Comunità', + community_reqs: 'minuscole, trattini bassi e nessuno spazio.', + edit: 'modifica', + reply: 'rispondi', + cancel: 'Annulla', + preview: 'Anteprima', + upload_image: 'carica immagine', + formatting_help: 'aiuto formattazione', + view_source: 'visualizza sorgente', + unlock: 'sblocca', + lock: 'blocca', + sticky: 'evidenzia', + unsticky: 'rimuovi evidenza', + link: 'link', + mod: 'moderatore', + mods: 'moderatori', + moderates: 'Moderatore di', + settings: 'Impostazioni', + remove_as_mod: 'rimuovi come moderatore', + appoint_as_mod: 'nomina come moderatore', + modlog: 'Registro di moderazione', + admin: 'amministratore', + admins: 'amministratori', + remove_as_admin: 'rimuovi come amministratore', + appoint_as_admin: 'nomina come amministratore', + remove: 'rimuovi', + removed: 'rimosso', + locked: 'bloccato', + stickied: 'evidenziato', + reason: 'Ragione', + mark_as_read: 'segna come letto', + mark_as_unread: 'segna come non letto', + delete: 'cancella', + deleted: 'cancellato', + delete_account: 'Cancella Account', + delete_account_confirm: 'Attenzione: stai per cancellare permanentemente tutti i tuoi dati. Sei sicuro?', + restore: 'ripristina', + ban: 'ban', + ban_from_site: 'banna dal sito', + unban: 'rimuovi ban', + unban_from_site: 'rimuove il ban dal sito', + banned: 'bannato', + save: 'salva', + unsave: 'rimuovi', + create: 'crea', + creator: 'autore', + username: 'Username', + email_or_username: 'Email o Username', + number_of_users: '{{count}} Utenti', + number_of_subscribers: '{{count}} Iscritti', + number_of_points: '{{count}} Punti', + number_online: '{{count}} Utenti Online', + name: 'Nome', + title: 'Titolo', + category: 'Categoria', + subscribers: 'Iscritti', + both: 'Entrambi', + saved: 'Salvato', + unsubscribe: 'Disiscriviti', + subscribe: 'Iscriviti', + subscribed: 'Iscritto', + prev: 'Precedente', + next: 'Prossima', + sidebar: 'Barra laterale', + sort_type: 'Ordina per', + hot: 'Popolari', + new: 'Nuovi', + top_day: 'Migliori della giornata', + week: 'Settimana', + month: 'Mese', + year: 'Anno', + all: 'Tutti', + top: 'Migliori', + api: 'API', + inbox: 'Posta in arrivo', + inbox_for: 'Posta di <1>{{user}}', + mark_all_as_read: 'segna tutti come letti', + type: 'Tipo', + unread: 'Non letti', + reply_sent: 'Risposta inviata', + search: 'Cerca', + overview: 'Panoramica', + view: 'Visualizza', + logout: 'Logout', + login_sign_up: 'Login / Iscriviti', + login: 'Login', + sign_up: 'Iscriviti', + notifications_error: 'Le notifiche desktop non sono supportate sul tuo browser. Prova Firefox o Chrome.', + unread_messages: 'Messaggi Non Letti', + password: 'Password', + verify_password: 'Verifica Password', + email: 'Email', + optional: 'Opzionale', + expires: 'Scade', + url: 'URL', + body: 'Contenuto', + copy_suggested_title: 'copia titolo suggerito: {{title}}', + community: 'Comunità', + expand_here: 'Visualizza qui', + subscribe_to_communities: 'Iscriviti ad una <1>comunità.', + chat: 'Chat', + recent_comments: 'Commenti Recenti', + no_results: 'Nessun risultato.', + setup: 'Setup', + lemmy_instance_setup: 'Setup dell\'istanza di Lemmy', + setup_admin: 'Imposta Amministratore del Sito', + your_site: 'il tuo sito', + modified: 'modificato', + nsfw: 'NSFW', + show_nsfw: 'Mostra contenuto NSFW', + theme: 'Tema', + sponsors: 'Sponsors', + sponsors_of_lemmy: 'Sponsors di Lemmy', + sponsor_message: 'Lemmy è un software gratuito e <1>open-source, il che significa nessuna pubblicità, monetizzazione o investitori esterni, per sempre. Le tue donazioni supportano direttamente lo sviluppo full-time del progetto. Si ringraziano le seguenti persone:', + support_on_patreon: 'Supporta su Patreon', + general_sponsors: 'I "General Sponsors" sono quelli che hanno investito dai 10$ ai 39$ su Lemmy.', + crypto: 'Crypto', + bitcoin: 'Bitcoin', + ethereum: 'Ethereum', + monero: 'Monero', + code: 'Code', + joined: 'Iscritto da', + by: 'di', + to: 'su', + transfer_community: 'trasferisci comunità', + transfer_site: 'trasferisci sito', + are_you_sure: 'sei sicuro?', + yes: 'si', + no: 'no', + powered_by: 'Powered by', + landing_0: 'Lemmy è un <1>aggregatore di link / alternativa a reddit, creato per integrarsi con il <2>fediverse. <3>È self-hosted, i commenti sono aggiornati in tempo reale ed è molto piccolo (<4>~80kB). La Federazione con la rete ActivityPub sarà implementata nel futuro. <5>Questa versione è una <6>beta molto giovane e molte funzionalità sono incomplete o mancanti. <7>Suggerisci nuove funzionalità o segnala errori a <8>questa pagina.<9>Sviluppato con <10>Rust, <11>Actix, <12>Inferno, <13>Typescript.', + not_logged_in: 'Non hai effettuato l\'accesso.', + community_ban: 'Sei stato bannato da questa comunità.', + site_ban: 'Sei stato bannato dal sito', + couldnt_create_comment: 'Impossibile creare il commento.', + couldnt_like_comment: 'Impossibile mettere \'Mi piace\' al commento.', + couldnt_update_comment: 'Impossibile aggiornare il commento.', + couldnt_save_comment: 'Impossibile salvare il commento.', + no_comment_edit_allowed: 'Non sei autorizzato a modificare il commento.', + no_post_edit_allowed: 'Non sei autorizzato a modificare il post.', + no_community_edit_allowed: 'Non sei autorizzato a modificare la comunità.', + couldnt_find_community: 'Impossibile trovare la comunità.', + couldnt_update_community: 'Impossibile aggiornare la comunità.', + community_already_exists: 'La comunità esiste già.', + community_moderator_already_exists: 'Questo utente è già moderatore della comunità.', + community_follower_already_exists: 'Questo utente è già moderatore della comunità.', + community_user_already_banned: 'L\'utente della comunità è già stato bannato.', + couldnt_create_post: 'Impossibile creare il post.', + couldnt_like_post: 'Impossibile mettere \'Mi piace\' post.', + couldnt_find_post: 'Impossibile trovare il post.', + couldnt_get_posts: 'Impossibile recuperare i post', + couldnt_update_post: 'Impossibile aggiornare il post', + couldnt_save_post: 'Impossibile salvare il post.', + no_slurs: 'Niente offese.', + not_an_admin: 'Non un amministratore.', + site_already_exists: 'Il sito esiste già.', + couldnt_update_site: 'Impossibile aggiornare il sito.', + couldnt_find_that_username_or_email: 'L\'username o la email non sono stati trovati.', + password_incorrect: 'Password non corretta.', + passwords_dont_match: 'Le password non corrispondono.', + admin_already_created: 'Spiacente, esiste già un amministratore.', + user_already_exists: 'L\'utente esiste già.', + couldnt_update_user: 'Impossibile aggiornare l\'utente.', + system_err_login: 'Si è verificato un errore. Prova ad effettuare nuovamente il login.', + }, +} diff --git a/ui/src/utils.ts b/ui/src/utils.ts index 350a8205a..4fec23f08 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -6,6 +6,7 @@ import 'moment/locale/fr'; import 'moment/locale/sv'; import 'moment/locale/ru'; import 'moment/locale/nl'; +import 'moment/locale/it'; import { UserOperation, Comment, User, SortType, ListingType, SearchType } from './interfaces'; import * as markdown_it from 'markdown-it'; @@ -231,6 +232,8 @@ export function getMomentLanguage(): string { lang = 'eo'; } else if (lang.startsWith('nl')) { lang = 'nl'; + } else if (lang.startsWith('it')) { + lang = 'it'; } else { lang = 'en'; } From 272361ea5fb3361c77d7868f4bbed083b7cdeddf Mon Sep 17 00:00:00 2001 From: Matteo Guglielmetti Date: Fri, 18 Oct 2019 10:33:29 +0200 Subject: [PATCH 009/381] Adds i18n to Prev and Next buttons in modlog --- ui/src/components/modlog.tsx | 45 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/ui/src/components/modlog.tsx b/ui/src/components/modlog.tsx index 3af122a8e..1c1a7bac3 100644 --- a/ui/src/components/modlog.tsx +++ b/ui/src/components/modlog.tsx @@ -8,6 +8,7 @@ import { msgOp, addTypeInfo, fetchLimit } from '../utils'; import { MomentTime } from './moment-time'; import * as moment from 'moment'; import { i18n } from '../i18next'; +import { T } from 'inferno-i18next'; interface ModlogState { combined: Array<{type_: string, data: ModRemovePost | ModLockPost | ModStickyPost | ModRemoveCommunity | ModAdd | ModBan}>, @@ -89,42 +90,42 @@ export class Modlog extends Component { {i.data.mod_user_name} - {i.type_ == 'removed_posts' && + {i.type_ == 'removed_posts' && <> - {(i.data as ModRemovePost).removed? 'Removed' : 'Restored'} + {(i.data as ModRemovePost).removed? 'Removed' : 'Restored'} Post {(i.data as ModRemovePost).post_name}
{(i.data as ModRemovePost).reason && ` reason: ${(i.data as ModRemovePost).reason}`}
} - {i.type_ == 'locked_posts' && + {i.type_ == 'locked_posts' && <> - {(i.data as ModLockPost).locked? 'Locked' : 'Unlocked'} + {(i.data as ModLockPost).locked? 'Locked' : 'Unlocked'} Post {(i.data as ModLockPost).post_name} } - {i.type_ == 'stickied_posts' && + {i.type_ == 'stickied_posts' && <> - {(i.data as ModStickyPost).stickied? 'Stickied' : 'Unstickied'} + {(i.data as ModStickyPost).stickied? 'Stickied' : 'Unstickied'} Post {(i.data as ModStickyPost).post_name} } - {i.type_ == 'removed_comments' && + {i.type_ == 'removed_comments' && <> - {(i.data as ModRemoveComment).removed? 'Removed' : 'Restored'} + {(i.data as ModRemoveComment).removed? 'Removed' : 'Restored'} Comment {(i.data as ModRemoveComment).comment_content} by {(i.data as ModRemoveComment).comment_user_name}
{(i.data as ModRemoveComment).reason && ` reason: ${(i.data as ModRemoveComment).reason}`}
} - {i.type_ == 'removed_communities' && + {i.type_ == 'removed_communities' && <> - {(i.data as ModRemoveCommunity).removed ? 'Removed' : 'Restored'} + {(i.data as ModRemoveCommunity).removed ? 'Removed' : 'Restored'} Community {(i.data as ModRemoveCommunity).community_name}
{(i.data as ModRemoveCommunity).reason && ` reason: ${(i.data as ModRemoveCommunity).reason}`}
{(i.data as ModRemoveCommunity).expires && ` expires: ${moment.utc((i.data as ModRemoveCommunity).expires).fromNow()}`}
} - {i.type_ == 'banned_from_community' && + {i.type_ == 'banned_from_community' && <> {(i.data as ModBanFromCommunity).banned ? 'Banned ' : 'Unbanned '} {(i.data as ModBanFromCommunity).other_user_name} @@ -134,7 +135,7 @@ export class Modlog extends Component {
{(i.data as ModBanFromCommunity).expires && ` expires: ${moment.utc((i.data as ModBanFromCommunity).expires).fromNow()}`}
} - {i.type_ == 'added_to_community' && + {i.type_ == 'added_to_community' && <> {(i.data as ModAddCommunity).removed ? 'Removed ' : 'Appointed '} {(i.data as ModAddCommunity).other_user_name} @@ -142,7 +143,7 @@ export class Modlog extends Component { {(i.data as ModAddCommunity).community_name} } - {i.type_ == 'banned' && + {i.type_ == 'banned' && <> {(i.data as ModBan).banned ? 'Banned ' : 'Unbanned '} {(i.data as ModBan).other_user_name} @@ -150,7 +151,7 @@ export class Modlog extends Component {
{(i.data as ModBan).expires && ` expires: ${moment.utc((i.data as ModBan).expires).fromNow()}`}
} - {i.type_ == 'added' && + {i.type_ == 'added' && <> {(i.data as ModAdd).removed ? 'Removed ' : 'Appointed '} {(i.data as ModAdd).other_user_name} @@ -170,8 +171,8 @@ export class Modlog extends Component { render() { return (
- {this.state.loading ? -
: + {this.state.loading ? +
:
{this.state.communityName && /c/{this.state.communityName} } @@ -199,21 +200,21 @@ export class Modlog extends Component { paginator() { return (
- {this.state.page > 1 && - + {this.state.page > 1 && + } - +
); } - nextPage(i: Modlog) { + nextPage(i: Modlog) { i.state.page++; i.setState(i.state); i.refetch(); } - prevPage(i: Modlog) { + prevPage(i: Modlog) { i.state.page--; i.setState(i.state); i.refetch(); @@ -239,6 +240,6 @@ export class Modlog extends Component { this.state.loading = false; window.scrollTo(0,0); this.setCombined(res); - } + } } } From 807399ead7b8509d28bd9af24caee0899cc1db91 Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 18 Oct 2019 19:03:23 +0000 Subject: [PATCH 010/381] =?UTF-8?q?Update=20README.md.=20Corrected=20Mot?= =?UTF-8?q?=C3=B6rhead=20spelling.=20(#307)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is impörtant! --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c4020efa..e7af4c5d9 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Each lemmy server can set its own moderation policy; appointing site-wide admins ## Why's it called Lemmy? -- Lead singer from [motorhead](https://invidio.us/watch?v=pWB5JZRGl0U). +- Lead singer from [Motörhead](https://invidio.us/watch?v=pWB5JZRGl0U). - The old school [video game](). - The [Koopa from Super Mario](https://www.mariowiki.com/Lemmy_Koopa). - The [furry rodents](http://sunchild.fpwc.org/lemming-the-little-giant-of-the-north/). From 1189e3f4ada6775d3bad91b89fa5b4cbfdb3a168 Mon Sep 17 00:00:00 2001 From: Quentin Date: Fri, 18 Oct 2019 21:10:07 +0200 Subject: [PATCH 011/381] ui: Add missing french translations (#308) --- README.md | 2 +- ui/src/translations/fr.ts | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e7af4c5d9..62a217d3c 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ lang | done | missing de | 82% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,settings,stickied,delete_account,delete_account_confirm,banned,creator,number_online,subscribed,expires,recent_comments,nsfw,show_nsfw,theme,crypto,monero,joined,by,to,transfer_community,transfer_site,are_you_sure,yes,no eo | 91% | number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,theme,are_you_sure,yes,no es | 100% | -fr | 95% | view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,creator,number_online,theme +fr | 100% | nl | 93% | preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,theme ru | 86% | cross_posts,cross_post,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,recent_comments,theme,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no sv | 100% | diff --git a/ui/src/translations/fr.ts b/ui/src/translations/fr.ts index 3786b10ce..7e86bf933 100644 --- a/ui/src/translations/fr.ts +++ b/ui/src/translations/fr.ts @@ -29,8 +29,11 @@ export const fr = { preview: 'prévisualiser', upload_image: 'téléverser une image', formatting_help: 'aide de formattage', + view_source: 'voir les sources', unlock: 'débloquer', lock: 'bloquer', + sticky: 'épingler', + unsticky: 'désépingler', link: 'lien', mod: 'modérateur', mods: 'modérateurs', @@ -46,11 +49,14 @@ export const fr = { remove: 'retirer', removed: 'retiré', locked: 'bloqué', + stickied: 'épinglé', reason: 'Raison', mark_as_read: 'marquer comme lu', mark_as_unread: 'marquer comme non-lu', delete: 'supprimer', deleted: 'supprimé', + delete_account: 'Supprimer le compte', + delete_account_confirm: 'Attention: cette action supprime toutes vos données de façons permanente. Entrez votre mot de passe pour confirmer.', restore: 'restaurer', ban: 'bannir', ban_from_site: 'bannir du site', @@ -60,11 +66,13 @@ export const fr = { save: 'sauvegarder', unsave: 'retirer', create: 'créer', + creator: 'createur', username: 'Nom d\'utilisateur', email_or_username: 'Email ou Nom d\'utilisateur', number_of_users:'{{count}} Utilisateurs', number_of_subscribers:'{{count}} Abonnés', number_of_points:'{{count}} Points', + number_online: '{{count}} Utilisateurs en ligne', name: 'Nom', title: 'Titre', category: 'Catégorie', @@ -123,6 +131,7 @@ export const fr = { modified: 'modifié', nsfw: 'Pas sûr pour le travail', show_nsfw: 'Afficher le contenu NSFW', + theme: 'Thème', sponsors: 'Sponsors', sponsors_of_lemmy: 'Sponsors de Lemmy', sponsor_message: 'Lemmy est gratuit et <1>open-source, c\'est à dire sans publicité et sans monétisation. Pour toujours. Vos dons soutiennent directement le développement du projet. Merci à nos soutiens.', From f3e93aeacceca7c35938b3672ab65a90aaf2e5d0 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Fri, 18 Oct 2019 12:13:09 -0700 Subject: [PATCH 012/381] Translation report instructions. --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 62a217d3c..80c4993c8 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,13 @@ ru | 86% | cross_posts,cross_post,number_of_communities,preview,upload_image,for sv | 100% | zh | 84% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,settings,stickied,delete_account,delete_account_confirm,banned,creator,number_online,recent_comments,nsfw,show_nsfw,theme,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no +If you'd like to update this report, run: + +```bash +cd ui +ts-node translation_report.ts > tmp # And replace the text above. +``` + ## Credits Logo made by Andy Cuccaro (@andycuccaro) under the CC-BY-SA 4.0 license From f140cfa847cbb648ae7551fa1d2fb6a489f60165 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Fri, 18 Oct 2019 12:14:28 -0700 Subject: [PATCH 013/381] Version v0.3.0.3 --- docker/prod/docker-compose.yml | 2 +- ui/src/version.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index 5c431eccd..aa6f4e403 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -10,7 +10,7 @@ services: volumes: - lemmy_db:/var/lib/postgresql/data lemmy: - image: dessalines/lemmy:v0.3.0.2 + image: dessalines/lemmy:v0.3.0.3 ports: - "127.0.0.1:8536:8536" environment: diff --git a/ui/src/version.ts b/ui/src/version.ts index 87b96ac46..5f8ad2c6b 100644 --- a/ui/src/version.ts +++ b/ui/src/version.ts @@ -1 +1 @@ -export let version: string = "v0.3.0.2-0-g9f5a328"; \ No newline at end of file +export let version: string = "v0.3.0.3-0-gf3e93ae"; \ No newline at end of file From 27ea8af9928c3789ee7425d2d3ed44987bf6831b Mon Sep 17 00:00:00 2001 From: Dessalines Date: Fri, 18 Oct 2019 13:58:43 -0700 Subject: [PATCH 014/381] Adding sponsors. --- ui/src/components/sponsors.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ui/src/components/sponsors.tsx b/ui/src/components/sponsors.tsx index 8f58812d6..5d0b1b172 100644 --- a/ui/src/components/sponsors.tsx +++ b/ui/src/components/sponsors.tsx @@ -3,9 +3,8 @@ import { WebSocketService } from '../services'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; -let general = - [ - "Nathan J. Goode", +let general = [ + "riccardo","NotTooHighToHack", ]; // let highlighted = []; // let silver = []; From 12624813b483071e2343af9d7629b66b2f8d25cf Mon Sep 17 00:00:00 2001 From: zacanger Date: Fri, 18 Oct 2019 15:56:32 -0600 Subject: [PATCH 015/381] chore: switch from tslint to eslint --- ui/.eslintrc.json | 57 ++ ui/package.json | 6 +- ui/src/components/symbols.tsx | 2 +- ui/tslint.json | 28 - ui/yarn.lock | 1296 ++++++++++++++++++++++++++++++++- 5 files changed, 1342 insertions(+), 47 deletions(-) create mode 100644 ui/.eslintrc.json delete mode 100644 ui/tslint.json diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json new file mode 100644 index 000000000..bee9e538f --- /dev/null +++ b/ui/.eslintrc.json @@ -0,0 +1,57 @@ +{ + "root": true, + "env": { + "browser": true + }, + "plugins": [ + "jane", + "inferno" + ], + "extends": [ + "plugin:jane/recommended", + "plugin:jane/typescript", + "plugin:inferno/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.json", + "warnOnUnsupportedTypeScriptVersion": false + }, + "rules": { + "@typescript-eslint/camelcase": 0, + "@typescript-eslint/member-delimiter-style": 0, + "@typescript-eslint/no-empty-interface": 0, + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-this-alias": 0, + "@typescript-eslint/no-unused-vars": 0, + "@typescript-eslint/no-use-before-define": 0, + "@typescript-eslint/no-useless-constructor": 0, + "arrow-body-style": 0, + "curly": 0, + "eol-last": 0, + "eqeqeq": 0, + "func-style": 0, + "import/no-duplicates": 0, + "inferno/jsx-key": 0, + "inferno/jsx-no-target-blank": 0, + "inferno/jsx-props-class-name": 0, + "inferno/no-direct-mutation-state": 0, + "inferno/no-unknown-property": 0, + "max-statements": 0, + "new-cap": 0, + "no-console": 0, + "no-duplicate-imports": 0, + "no-extra-parens": 0, + "no-return-assign": 0, + "no-throw-literal": 0, + "no-trailing-spaces": 0, + "no-unused-expressions": 0, + "no-useless-constructor": 0, + "no-useless-escape": 0, + "no-var": 0, + "prefer-const": 0, + "prefer-rest-params": 0, + "quote-props": 0, + "unicorn/filename-case": 0 + } +} diff --git a/ui/package.json b/ui/package.json index 3537a2ac3..603faf0b9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "start": "node fuse dev", - "build": "node fuse prod" + "build": "node fuse prod", + "lint": "eslint --report-unused-disable-directives --ext .js,.ts,.tsx src" }, "keywords": [], "author": "Dessalines", @@ -43,6 +44,9 @@ }, "devDependencies": { "@types/i18next": "^12.1.0", + "eslint": "^6.5.1", + "eslint-plugin-inferno": "^7.14.3", + "eslint-plugin-jane": "^7.0.0", "fuse-box": "^3.1.3", "ts-transform-classcat": "^0.0.2", "ts-transform-inferno": "^4.0.2", diff --git a/ui/src/components/symbols.tsx b/ui/src/components/symbols.tsx index e2803fb7d..a299ff253 100644 --- a/ui/src/components/symbols.tsx +++ b/ui/src/components/symbols.tsx @@ -8,7 +8,7 @@ export class Symbols extends Component { render() { return ( -
-