diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/follow_requests/follow_requests.js | 23 | ||||
| -rw-r--r-- | src/components/follow_requests/follow_requests.vue | 12 | ||||
| -rw-r--r-- | src/components/login_form/login_form.vue | 2 | ||||
| -rw-r--r-- | src/components/nav_panel/nav_panel.vue | 5 | ||||
| -rw-r--r-- | src/components/post_status_form/post_status_form.js | 23 | ||||
| -rw-r--r-- | src/components/post_status_form/post_status_form.vue | 35 | ||||
| -rw-r--r-- | src/components/settings/settings.vue | 3 | ||||
| -rw-r--r-- | src/components/user_card/user_card.js | 11 | ||||
| -rw-r--r-- | src/components/user_card/user_card.vue | 11 | ||||
| -rw-r--r-- | src/components/user_card_content/user_card_content.vue | 2 | ||||
| -rw-r--r-- | src/components/user_settings/user_settings.js | 4 | ||||
| -rw-r--r-- | src/components/user_settings/user_settings.vue | 23 | ||||
| -rw-r--r-- | src/i18n/messages.js | 213 | ||||
| -rw-r--r-- | src/main.js | 5 | ||||
| -rw-r--r-- | src/modules/api.js | 10 | ||||
| -rw-r--r-- | src/services/api/api.service.js | 40 | ||||
| -rw-r--r-- | src/services/backend_interactor_service/backend_interactor_service.js | 14 | ||||
| -rw-r--r-- | src/services/status_poster/status_poster.service.js | 4 |
18 files changed, 404 insertions, 36 deletions
diff --git a/src/components/follow_requests/follow_requests.js b/src/components/follow_requests/follow_requests.js new file mode 100644 index 00000000..11a228aa --- /dev/null +++ b/src/components/follow_requests/follow_requests.js @@ -0,0 +1,23 @@ +import UserCard from '../user_card/user_card.vue' + +const FollowRequests = { + components: { + UserCard + }, + created () { + this.updateRequests() + }, + computed: { + requests () { + return this.$store.state.api.followRequests + } + }, + methods: { + updateRequests () { + this.$store.state.api.backendInteractor.fetchFollowRequests() + .then((requests) => { this.$store.commit('setFollowRequests', requests) }) + } + } +} + +export default FollowRequests diff --git a/src/components/follow_requests/follow_requests.vue b/src/components/follow_requests/follow_requests.vue new file mode 100644 index 00000000..87dc4194 --- /dev/null +++ b/src/components/follow_requests/follow_requests.vue @@ -0,0 +1,12 @@ +<template> + <div class="settings panel panel-default"> + <div class="panel-heading"> + {{$t('nav.friend_requests')}} + </div> + <div class="panel-body"> + <user-card v-for="request in requests" :key="request.id" :user="request" :showFollows="false" :showApproval="true"></user-card> + </div> + </div> +</template> + +<script src="./follow_requests.js"></script> diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue index 67fa95a8..b7fed48a 100644 --- a/src/components/login_form/login_form.vue +++ b/src/components/login_form/login_form.vue @@ -8,7 +8,7 @@ <form v-on:submit.prevent='submit(user)' class='login-form'> <div class='form-group'> <label for='username'>{{$t('login.username')}}</label> - <input :disabled="loggingIn" v-model='user.username' class='form-control' id='username' placeholder='e.g. lain'> + <input :disabled="loggingIn" v-model='user.username' class='form-control' id='username' v-bind:placeholder="$t('login.placeholder')"> </div> <div class='form-group'> <label for='password'>{{$t('login.password')}}</label> diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue index 2e1a6c7a..0b188f9a 100644 --- a/src/components/nav_panel/nav_panel.vue +++ b/src/components/nav_panel/nav_panel.vue @@ -12,6 +12,11 @@ {{ $t("nav.mentions") }} </router-link> </li> + <li v-if='currentUser && currentUser.locked'> + <router-link to='/friend-requests'> + {{ $t("nav.friend_requests") }} + </router-link> + </li> <li> <router-link to='/main/public'> {{ $t("nav.public_tl") }} diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index e6742580..0597d652 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -48,12 +48,21 @@ const PostStatusForm = { highlighted: 0, newStatus: { status: statusText, - files: [] + files: [], + visibility: 'public' }, caret: 0 } }, computed: { + vis () { + return { + public: { selected: this.newStatus.visibility === 'public' }, + unlisted: { selected: this.newStatus.visibility === 'unlisted' }, + private: { selected: this.newStatus.visibility === 'private' }, + direct: { selected: this.newStatus.visibility === 'direct' } + } + }, candidates () { const firstchar = this.textAtCaret.charAt(0) if (firstchar === '@') { @@ -118,6 +127,9 @@ const PostStatusForm = { }, isOverLengthLimit () { return this.hasStatusLengthLimit && (this.statusLength > this.statusLengthLimit) + }, + scopeOptionsEnabled () { + return this.$store.state.config.scopeOptionsEnabled } }, methods: { @@ -185,6 +197,8 @@ const PostStatusForm = { this.posting = true statusPoster.postStatus({ status: newStatus.status, + spoilerText: newStatus.spoilerText || null, + visibility: newStatus.visibility, media: newStatus.files, store: this.$store, inReplyToStatusId: this.replyTo @@ -192,7 +206,8 @@ const PostStatusForm = { if (!data.error) { this.newStatus = { status: '', - files: [] + files: [], + visibility: newStatus.visibility } this.$emit('posted') let el = this.$el.querySelector('textarea') @@ -239,6 +254,7 @@ const PostStatusForm = { e.dataTransfer.dropEffect = 'copy' }, resize (e) { + if (!e.target) { return } const vertPadding = Number(window.getComputedStyle(e.target)['padding-top'].substr(0, 1)) + Number(window.getComputedStyle(e.target)['padding-bottom'].substr(0, 1)) e.target.style.height = 'auto' @@ -249,6 +265,9 @@ const PostStatusForm = { }, clearError () { this.error = null + }, + changeVis (visibility) { + this.newStatus.visibility = visibility } } } diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index 28dd227e..802d51ed 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -2,6 +2,12 @@ <div class="post-status-form"> <form @submit.prevent="postStatus(newStatus)"> <div class="form-group" > + <input + v-if="scopeOptionsEnabled" + type="text" + :placeholder="$t('post_status.content_warning')" + v-model="newStatus.spoilerText" + class="form-cw"> <textarea ref="textarea" @click="setCaret" @@ -18,6 +24,12 @@ @input="resize" @paste="paste"> </textarea> + <div v-if="scopeOptionsEnabled" class="visibility-tray"> + <i v-on:click="changeVis('direct')" class="icon-mail-alt" :class="vis.direct"></i> + <i v-on:click="changeVis('private')" class="icon-lock" :class="vis.private"></i> + <i v-on:click="changeVis('unlisted')" class="icon-lock-open-alt" :class="vis.unlisted"></i> + <i v-on:click="changeVis('public')" class="icon-globe" :class="vis.public"></i> + </div> </div> <div style="position:relative;" v-if="candidates"> <div class="autocomplete-panel"> @@ -79,6 +91,17 @@ } } +.post-status-form .visibility-tray { + font-size: 1.2em; + padding: 3px; + cursor: pointer; + + .selected { + color: $fallback--lightFg; + color: var(--lightFg, $fallback--lightFg); + } +} + .post-status-form, .login { .form-bottom { display: flex; @@ -143,7 +166,15 @@ line-height:24px; } - form textarea { + form textarea.form-cw { + line-height:16px; + resize: none; + overflow: hidden; + transition: min-height 200ms 100ms; + min-height: 1px; + } + + form textarea.form-control { line-height:16px; resize: none; overflow: hidden; @@ -152,7 +183,7 @@ box-sizing: content-box; } - form textarea:focus { + form textarea.form-control:focus { min-height: 48px; } diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index b4514ba1..6245e758 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -57,7 +57,10 @@ @import '../../_variables.scss'; .setting-item { + border-bottom: 2px solid var(--btn, $fallback--btn); margin: 1em 1em 1.4em; + padding-bottom: 1.4em; + textarea { width: 100%; diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index a7a871c3..a019627a 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -3,7 +3,8 @@ import UserCardContent from '../user_card_content/user_card_content.vue' const UserCard = { props: [ 'user', - 'showFollows' + 'showFollows', + 'showApproval' ], data () { return { @@ -16,6 +17,14 @@ const UserCard = { methods: { toggleUserExpanded () { this.userExpanded = !this.userExpanded + }, + approveUser () { + this.$store.state.api.backendInteractor.approveUser(this.user.id) + this.$store.dispatch('removeFollowRequest', this.user) + }, + denyUser () { + this.$store.state.api.backendInteractor.denyUser(this.user.id) + this.$store.dispatch('removeFollowRequest', this.user) } } } diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index 51d6965f..6478a65f 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -15,6 +15,10 @@ </div> <a :href="user.statusnet_profile_url" target="blank"><div class="user-screen-name">@{{ user.screen_name }}</div></a> </div> + <div class="approval" v-if="showApproval"> + <button class="btn btn-default" @click="approveUser">{{ $t('user_card.approve') }}</button> + <button class="btn btn-default" @click="denyUser">{{ $t('user_card.deny') }}</button> + </div> </div> </template> @@ -75,4 +79,11 @@ margin-bottom: 0; } } + +.approval { + button { + width: 100%; + margin-bottom: 0.5em; + } +} </style> diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index c120df9a..09e91271 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -15,7 +15,7 @@ <div class="name-and-screen-name"> <div :title="user.name" class='user-name'>{{user.name}}</div> <router-link class='user-screen-name':to="{ name: 'user-profile', params: { id: user.id } }"> - <span>@{{user.screen_name}}</span> + <span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span> <span class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span> </router-link> </div> diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index b6026e18..443e63dd 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -5,6 +5,7 @@ const UserSettings = { return { newname: this.$store.state.users.currentUser.name, newbio: this.$store.state.users.currentUser.description, + newlocked: this.$store.state.users.currentUser.locked, followList: null, followImportError: false, followsImported: false, @@ -34,7 +35,8 @@ const UserSettings = { updateProfile () { const name = this.newname const description = this.newbio - this.$store.state.api.backendInteractor.updateProfile({params: {name, description}}).then((user) => { + const locked = this.newlocked + this.$store.state.api.backendInteractor.updateProfile({params: {name, description, locked}}).then((user) => { if (!user.error) { this.$store.commit('addNewUsers', [user]) this.$store.commit('setCurrentUser', user) diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index fbf3f651..881b0fa1 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -5,15 +5,19 @@ </div> <div class="panel-body profile-edit"> <div class="setting-item"> - <h3>{{$t('settings.name_bio')}}</h3> + <h2>{{$t('settings.name_bio')}}</h2> <p>{{$t('settings.name')}}</p> <input class='name-changer' id='username' v-model="newname"></input> <p>{{$t('settings.bio')}}</p> <textarea class="bio" v-model="newbio"></textarea> + <div class="setting-item"> + <input type="checkbox" v-model="newlocked" id="account-locked"> + <label for="account-locked">{{$t('settings.lock_account_description')}}</label> + </div> <button :disabled='newname.length <= 0' class="btn btn-default" @click="updateProfile">{{$t('general.submit')}}</button> </div> <div class="setting-item"> - <h3>{{$t('settings.avatar')}}</h3> + <h2>{{$t('settings.avatar')}}</h2> <p>{{$t('settings.current_avatar')}}</p> <img :src="user.profile_image_url_original" class="old-avatar"></img> <p>{{$t('settings.set_new_avatar')}}</p> @@ -26,7 +30,7 @@ <button class="btn btn-default" v-else-if="previews[0]" @click="submitAvatar">{{$t('general.submit')}}</button> </div> <div class="setting-item"> - <h3>{{$t('settings.profile_banner')}}</h3> + <h2>{{$t('settings.profile_banner')}}</h2> <p>{{$t('settings.current_profile_banner')}}</p> <img :src="user.cover_photo" class="banner"></img> <p>{{$t('settings.set_new_profile_banner')}}</p> @@ -39,7 +43,7 @@ <button class="btn btn-default" v-else-if="previews[1]" @click="submitBanner">{{$t('general.submit')}}</button> </div> <div class="setting-item"> - <h3>{{$t('settings.profile_background')}}</h3> + <h2>{{$t('settings.profile_background')}}</h2> <p>{{$t('settings.set_new_profile_background')}}</p> <img class="bg" v-bind:src="previews[2]" v-if="previews[2]"> </img> @@ -50,7 +54,7 @@ <button class="btn btn-default" v-else-if="previews[2]" @click="submitBg">{{$t('general.submit')}}</button> </div> <div class="setting-item"> - <h3>{{$t('settings.change_password')}}</h3> + <h2>{{$t('settings.change_password')}}</h2> <div> <p>{{$t('settings.current_password')}}</p> <input type="password" v-model="changePasswordInputs[0]"> @@ -69,7 +73,7 @@ <p v-if="changePasswordError">{{changePasswordError}}</p> </div> <div class="setting-item" v-if="pleromaBackend"> - <h3>{{$t('settings.follow_import')}}</h3> + <h2>{{$t('settings.follow_import')}}</h2> <p>{{$t('settings.import_followers_from_a_csv_file')}}</p> <form v-model="followImportForm"> <input type="file" ref="followlist" v-on:change="followListChange"></input> @@ -86,15 +90,15 @@ </div> </div> <div class="setting-item" v-if="enableFollowsExport"> - <h3>{{$t('settings.follow_export')}}</h3> + <h2>{{$t('settings.follow_export')}}</h2> <button class="btn btn-default" @click="exportFollows">{{$t('settings.follow_export_button')}}</button> </div> <div class="setting-item" v-else> - <h3>{{$t('settings.follow_export_processing')}}</h3> + <h2>{{$t('settings.follow_export_processing')}}</h2> </div> <hr> <div class="setting-item"> - <h3>{{$t('settings.delete_account')}}</h3> + <h2>{{$t('settings.delete_account')}}</h2> <p v-if="!deletingAccount">{{$t('settings.delete_account_description')}}</p> <div v-if="deletingAccount"> <p>{{$t('settings.delete_account_instructions')}}</p> @@ -121,6 +125,7 @@ input[type=file] { padding: 5px; + height: auto; } .banner { diff --git a/src/i18n/messages.js b/src/i18n/messages.js index 5009418f..3a9f2e63 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -103,6 +103,7 @@ const de = { login: { login: 'Anmelden', username: 'Benutzername', + placeholder: 'z.B. lain', password: 'Passwort', register: 'Registrieren', logout: 'Abmelden' @@ -199,6 +200,7 @@ const fi = { login: { login: 'Kirjaudu sisään', username: 'Käyttäjänimi', + placeholder: 'esim. lain', password: 'Salasana', register: 'Rekisteröidy', logout: 'Kirjaudu ulos' @@ -233,7 +235,8 @@ const en = { timeline: 'Timeline', mentions: 'Mentions', public_tl: 'Public Timeline', - twkn: 'The Whole Known Network' + twkn: 'The Whole Known Network', + friend_requests: 'Follow Requests' }, user_card: { follows_you: 'Follows you!', @@ -247,7 +250,9 @@ const en = { followers: 'Followers', followees: 'Following', per_day: 'per day', - remote_follow: 'Remote follow' + remote_follow: 'Remote follow', + approve: 'Approve', + deny: 'Deny' }, timeline: { show_new: 'Show new', @@ -317,7 +322,8 @@ const en = { new_password: 'New password', confirm_new_password: 'Confirm new password', changed_password: 'Password changed successfully!', - change_password_error: 'There was an issue changing your password.' + change_password_error: 'There was an issue changing your password.', + lock_account_description: 'Restrict your account to approved followers only' }, notifications: { notifications: 'Notifications', @@ -329,6 +335,7 @@ const en = { login: { login: 'Log in', username: 'Username', + placeholder: 'e.g. lain', password: 'Password', register: 'Register', logout: 'Log out' @@ -342,6 +349,7 @@ const en = { }, post_status: { posting: 'Posting', + content_warning: 'Subject (optional)', default: 'Just landed in L.A.' }, finder: { @@ -448,6 +456,7 @@ const eo = { login: { login: 'Saluti', username: 'Salutnomo', + placeholder: 'ekz. lain', password: 'Pasvorto', register: 'Registriĝi', logout: 'Adiaŭi' @@ -535,6 +544,7 @@ const et = { login: { login: 'Logi sisse', username: 'Kasutajanimi', + placeholder: 'nt lain', password: 'Parool', register: 'Registreeru', logout: 'Logi välja' @@ -618,6 +628,7 @@ const hu = { login: { login: 'Bejelentkezés', username: 'Felhasználó név', + placeholder: 'e.g. lain', password: 'Jelszó', register: 'Feliratkozás', logout: 'Kijelentkezés' @@ -701,6 +712,7 @@ const ro = { login: { login: 'Loghează', username: 'Nume utilizator', + placeholder: 'd.e. lain', password: 'Parolă', register: 'Înregistrare', logout: 'Deloghează' @@ -816,6 +828,7 @@ const ja = { login: { login: 'ログイン', username: 'ユーザー名', + placeholder: '例えば lain', password: 'パスワード', register: '登録', logout: 'ログアウト' @@ -905,10 +918,13 @@ const fr = { text: 'Texte', links: 'Liens', streaming: 'Charger automatiquement les nouveaux statuts lorsque vous êtes au haut de la page', - follow_import: 'Importer ses abonnements', - import_followers_from_a_csv_file: 'Importer ses abonnements depuis un fichier csv', + follow_import: 'Importer des abonnements', + import_followers_from_a_csv_file: 'Importer des abonnements depuis un fichier csv', follows_imported: 'Abonnements importés ! Le traitement peut prendre un moment.', follow_import_error: 'Erreur lors de l\'importation des abonnements.', + follow_export: 'Exporter les abonnements', + follow_export_button: 'Exporter les abonnements en csv', + follow_export_processing: 'Exportation en cours...', cBlue: 'Bleu (Répondre, suivre)', cRed: 'Rouge (Annuler)', cOrange: 'Orange (Aimer)', @@ -921,7 +937,15 @@ const fr = { tooltipRadius: 'Info-bulles/alertes ', attachmentRadius: 'Pièces jointes', radii_help: 'Vous pouvez ici choisir le niveau d\'arrondi des angles de l\'interface (en pixels)', - stop_gifs: 'N\'animer les GIFS que lors du survol du curseur de la souris' + stop_gifs: 'N\'animer les GIFS que lors du survol du curseur de la souris', + change_password: 'Modifier son mot de passe', + current_password: 'Mot de passe actuel', + new_password: 'Nouveau mot de passe', + confirm_new_password: 'Confirmation du nouveau mot de passe', + delete_account: 'Supprimer le compte', + delete_account_description: 'Supprimer définitivement votre compte et tous vos statuts.', + delete_account_instructions: 'Indiquez votre mot de passe ci-dessous pour confirmer la suppression de votre compte.', + delete_account_error: 'Il y a eu un problème lors de la tentative de suppression de votre compte. Si le problème persiste, contactez l\'administrateur de cette instance.' }, notifications: { notifications: 'Notifications', @@ -933,6 +957,7 @@ const fr = { login: { login: 'Connexion', username: 'Identifiant', + placeholder: 'p.e. lain', password: 'Mot de passe', register: 'S\'inscrire', logout: 'Déconnexion' @@ -1111,6 +1136,7 @@ const oc = { login: { login: 'Connexion', username: 'Nom d’utilizaire', + placeholder: 'e.g. lain', password: 'Senhal', register: 'Se marcar', logout: 'Desconnexion' @@ -1200,13 +1226,14 @@ const pl = { cOrange: 'Pomarańczowy (ulubione)', cGreen: 'Zielony (powtórzenia)', btnRadius: 'Przyciski', + inputRadius: 'Pola tekstowe', panelRadius: 'Panele', avatarRadius: 'Awatary', avatarAltRadius: 'Awatary (powiadomienia)', tooltipRadius: 'Etykiety/alerty', attachmentRadius: 'Załączniki', filtering: 'Filtrowanie', - filtering_explanation: 'Wszystkie statusy zawierające te słowa będą wyciszone. Jedno słowo na linijkę', + filtering_explanation: 'Wszystkie statusy zawierające te słowa będą wyciszone. Jedno słowo na linijkę.', attachments: 'Załączniki', hide_attachments_in_tl: 'Ukryj załączniki w osi czasu', hide_attachments_in_convo: 'Ukryj załączniki w rozmowach', @@ -1218,7 +1245,20 @@ const pl = { follow_import: 'Import obserwowanych', import_followers_from_a_csv_file: 'Importuj obserwowanych z pliku CSV', follows_imported: 'Obserwowani zaimportowani! Przetwarzanie może trochę potrwać.', - follow_import_error: 'Błąd przy importowaniu obserwowanych' + follow_import_error: 'Błąd przy importowaniu obserwowanych', + delete_account: 'Usuń konto', + delete_account_description: 'Trwale usuń konto i wszystkie posty.', + delete_account_instructions: 'Wprowadź swoje hasło w poniższe pole aby potwierdzić usunięcie konta.', + delete_account_error: 'Wystąpił problem z usuwaniem twojego konta. Jeżeli problem powtarza się, poinformuj administratora swojej instancji.', + follow_export: 'Eksport obserwowanych', + follow_export_processing: 'Przetwarzanie, wkrótce twój plik zacznie się ściągać.', + follow_export_button: 'Eksportuj swoją listę obserwowanych do pliku CSV', + change_password: 'Zmień hasło', + current_password: 'Obecne hasło', + new_password: 'Nowe hasło', + confirm_new_password: 'Potwierdź nowe hasło', + changed_password: 'Hasło zmienione poprawnie!', + change_password_error: 'Podczas zmiany hasła wystąpił problem.' }, notifications: { notifications: 'Powiadomienia', @@ -1230,6 +1270,7 @@ const pl = { login: { login: 'Zaloguj', username: 'Użytkownik', + placeholder: 'n.p. lain', password: 'Hasło', register: 'Zarejestruj', logout: 'Wyloguj' @@ -1333,6 +1374,7 @@ const es = { login: { login: 'Identificación', username: 'Usuario', + placeholder: 'p.ej. lain', password: 'Contraseña', register: 'Registrar', logout: 'Salir' @@ -1433,6 +1475,7 @@ const pt = { login: { login: 'Entrar', username: 'Usuário', + placeholder: 'p.e. lain', password: 'Senha', register: 'Registrar', logout: 'Sair' @@ -1538,7 +1581,20 @@ const ru = { follow_import: 'Импортировать читаемых', import_followers_from_a_csv_file: 'Импортировать читаемых из файла .csv', follows_imported: 'Список читаемых импортирован. Обработка займёт некоторое время..', - follow_import_error: 'Ошибка при импортировании читаемых.' + follow_import_error: 'Ошибка при импортировании читаемых.', + delete_account: 'Удалить аккаунт', + delete_account_description: 'Удалить ваш аккаунт и все ваши сообщения.', + delete_account_instructions: 'Введите ваш пароль в поле ниже для подтверждения удаления.', + delete_account_error: 'Возникла ошибка в процессе удаления вашего аккаунта. Если это повторяется, свяжитесь с администратором вашего сервера.', + follow_export: 'Экспортировать читаемых', + follow_export_processing: 'Ведётся обработка, скоро вам будет предложено загрузить файл', + follow_export_button: 'Экспортировать читаемых в файл .csv', + change_password: 'Сменить пароль', + current_password: 'Текущий пароль', + new_password: 'Новый пароль', + confirm_new_password: 'Подтверждение нового пароля', + changed_password: 'Пароль изменён успешно.', + change_password_error: 'Произошла ошибка при попытке изменить пароль.' }, notifications: { notifications: 'Уведомления', @@ -1550,6 +1606,7 @@ const ru = { login: { login: 'Войти', username: 'Имя пользователя', + placeholder: 'e.c. lain', password: 'Пароль', register: 'Зарегистрироваться', logout: 'Выйти' @@ -1668,6 +1725,7 @@ const nb = { login: { login: 'Logg inn', username: 'Brukernavn', + placeholder: 'f. eks lain', password: 'Passord', register: 'Registrer', logout: 'Logg ut' @@ -1696,6 +1754,140 @@ const nb = { } } +const he = { + chat: { + title: 'צ\'אט' + }, + nav: { + chat: 'צ\'אט מקומי', + timeline: 'ציר הזמן', + mentions: 'אזכורים', + public_tl: 'ציר הזמן הציבורי', + twkn: 'כל הרשת הידועה' + }, + user_card: { + follows_you: 'עוקב אחריך!', + following: 'עוקב!', + follow: 'עקוב', + blocked: 'חסום!', + block: 'חסימה', + statuses: 'סטטוסים', + mute: 'השתק', + muted: 'מושתק', + followers: 'עוקבים', + followees: 'נעקבים', + per_day: 'ליום', + remote_follow: 'עקיבה מרחוק' + }, + timeline: { + show_new: 'הראה חדש', + error_fetching: 'שגיאה בהבאת הודעות', + up_to_date: 'עדכני', + load_older: 'טען סטטוסים חדשים', + conversation: 'שיחה', + collapse: 'מוטט', + repeated: 'חזר' + }, + settings: { + user_settings: 'הגדרות משתמש', + name_bio: 'שם ואודות', + name: 'שם', + bio: 'אודות', + avatar: 'תמונת פרופיל', + current_avatar: 'תמונת הפרופיל הנוכחית שלך', + set_new_avatar: 'קבע תמונת פרופיל חדשה', + profile_banner: 'כרזת הפרופיל', + current_profile_banner: 'כרזת הפרופיל הנוכחית שלך', + set_new_profile_banner: 'קבע כרזת פרופיל חדשה', + profile_background: 'רקע הפרופיל', + set_new_profile_background: 'קבע רקע פרופיל חדש', + settings: 'הגדרות', + theme: 'תמה', + presets: 'ערכים קבועים מראש', + theme_help: 'השתמש בקודי צבע הקס (#אדום-אדום-ירוק-ירוק-כחול-כחול) על מנת להתאים אישית את תמת הצבע שלך.', + radii_help: 'קבע מראש עיגול פינות לממשק (בפיקסלים)', + background: 'רקע', + foreground: 'חזית', + text: 'טקסט', + links: 'לינקים', + cBlue: 'כחול (תגובה, עקיבה)', + cRed: 'אדום (ביטול)', + cOrange: 'כתום (לייק)', + cGreen: 'ירוק (חזרה)', + btnRadius: 'כפתורים', + inputRadius: 'שדות קלט', + panelRadius: 'פאנלים', + avatarRadius: 'תמונות פרופיל', + avatarAltRadius: 'תמונות פרופיל (התראות)', + tooltipRadius: 'טולטיפ \\ התראות', + attachmentRadius: 'צירופים', + filtering: 'סינון', + filtering_explanation: 'כל הסטטוסים הכוללים את המילים הללו יושתקו, אחד לשורה', + attachments: 'צירופים', + hide_attachments_in_tl: 'החבא צירופים בציר הזמן', + hide_attachments_in_convo: 'החבא צירופים בשיחות', + nsfw_clickthrough: 'החל החבאת צירופים לא בטוחים לצפיה בעת עבודה בעזרת לחיצת עכבר', + stop_gifs: 'נגן-בעת-ריחוף GIFs', + autoload: 'החל טעינה אוטומטית בגלילה לתחתית הדף', + streaming: 'החל זרימת הודעות אוטומטית בעת גלילה למעלה הדף', + reply_link_preview: 'החל תצוגה מקדימה של לינק-תגובה בעת ריחוף עם העכבר', + follow_import: 'יבוא עקיבות', + import_followers_from_a_csv_file: 'ייבא את הנעקבים שלך מקובץ csv', + follows_imported: 'נעקבים יובאו! ייקח זמן מה לעבד אותם.', + follow_import_error: 'שגיאה בייבוא נעקבים.', + delete_account: 'מחק משתמש', + delete_account_description: 'מחק לצמיתות את המשתמש שלך ואת כל הודעותיך.', + delete_account_instructions: 'הכנס את סיסמתך בקלט למטה על מנת לאשר מחיקת משתמש.', + delete_account_error: 'הייתה בעיה במחיקת המשתמש. אם זה ממשיך, אנא עדכן את מנהל השרת שלך.', + follow_export: 'יצוא עקיבות', + follow_export_processing: 'טוען. בקרוב תתבקש להוריד את הקובץ את הקובץ שלך', + follow_export_button: 'ייצא את הנעקבים שלך לקובץ csv', + change_password: 'שנה סיסמה', + current_password: 'סיסמה נוכחית', + new_password: 'סיסמה חדשה', + confirm_new_password: 'אשר סיסמה', + changed_password: 'סיסמה שונתה בהצלחה!', + change_password_error: 'הייתה בעיה בשינוי סיסמתך.' + }, + notifications: { + notifications: 'התראות', + read: 'קרא!', + followed_you: 'עקב אחריך!', + favorited_you: 'אהב את הסטטוס שלך', + repeated_you: 'חזר על הסטטוס שלך' + }, + login: { + login: 'התחבר', + username: 'שם המשתמש', + placeholder: 'למשל lain', + password: 'סיסמה', + register: 'הירשם', + logout: 'התנתק' + }, + registration: { + registration: 'הרשמה', + fullname: 'שם תצוגה', + email: 'אימייל', + bio: 'אודות', + password_confirm: 'אישור סיסמה' + }, + post_status: { + posting: 'מפרסם', + default: 'הרגע נחת ב-ל.א.' + }, + finder: { + find_user: 'מציאת משתמש', + error_fetching_user: 'שגיאה במציאת משתמש' + }, + general: { + submit: 'שלח', + apply: 'החל' + }, + user_profile: { + timeline_title: 'ציר זמן המשתמש' + } +} + const messages = { de, fi, @@ -1712,7 +1904,8 @@ const messages = { es, pt, ru, - nb + nb, + he } export default messages diff --git a/src/main.js b/src/main.js index 3c4a072b..bacd7f6d 100644 --- a/src/main.js +++ b/src/main.js @@ -12,6 +12,7 @@ import UserProfile from './components/user_profile/user_profile.vue' import Settings from './components/settings/settings.vue' import Registration from './components/registration/registration.vue' import UserSettings from './components/user_settings/user_settings.vue' +import FollowRequests from './components/follow_requests/follow_requests.vue' import statusesModule from './modules/statuses.js' import usersModule from './modules/users.js' @@ -88,7 +89,7 @@ window.fetch('/api/statusnet/config.json') window.fetch('/static/config.json') .then((res) => res.json()) .then((data) => { - const {theme, background, logo, showWhoToFollowPanel, whoToFollowProvider, whoToFollowLink, showInstanceSpecificPanel} = data + const {theme, background, logo, showWhoToFollowPanel, whoToFollowProvider, whoToFollowLink, showInstanceSpecificPanel, scopeOptionsEnabled} = data store.dispatch('setOption', { name: 'theme', value: theme }) store.dispatch('setOption', { name: 'background', value: background }) store.dispatch('setOption', { name: 'logo', value: logo }) @@ -96,6 +97,7 @@ window.fetch('/static/config.json') store.dispatch('setOption', { name: 'whoToFollowProvider', value: whoToFollowProvider }) store.dispatch('setOption', { name: 'whoToFollowLink', value: whoToFollowLink }) store.dispatch('setOption', { name: 'showInstanceSpecificPanel', value: showInstanceSpecificPanel }) + store.dispatch('setOption', { name: 'scopeOptionsEnabled', value: scopeOptionsEnabled }) if (data['chatDisabled']) { store.dispatch('disableChat') } @@ -117,6 +119,7 @@ window.fetch('/static/config.json') { name: 'mentions', path: '/:username/mentions', component: Mentions }, { name: 'settings', path: '/settings', component: Settings }, { name: 'registration', path: '/registration', component: Registration }, + { name: 'friend-requests', path: '/friend-requests', component: FollowRequests }, { name: 'user-settings', path: '/user-settings', component: UserSettings } ] diff --git a/src/modules/api.js b/src/modules/api.js index c91fb97b..a61340c2 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -7,7 +7,8 @@ const api = { backendInteractor: backendInteractorService(), fetchers: {}, socket: null, - chatDisabled: false + chatDisabled: false, + followRequests: [] }, mutations: { setBackendInteractor (state, backendInteractor) { @@ -24,6 +25,9 @@ const api = { }, setChatDisabled (state, value) { state.chatDisabled = value + }, + setFollowRequests (state, value) { + state.followRequests = value } }, actions: { @@ -57,6 +61,10 @@ const api = { }, disableChat (store) { store.commit('setChatDisabled', true) + }, + removeFollowRequest (store, request) { + let requests = store.state.followRequests.filter((it) => it !== request) + store.commit('setFollowRequests', requests) } } } diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 65761aee..d1659784 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -32,6 +32,9 @@ const USER_URL = '/api/users/show.json' const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import' const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account' const CHANGE_PASSWORD_URL = '/api/pleroma/change_password' +const FOLLOW_REQUESTS_URL = '/api/pleroma/friend_requests' +const APPROVE_USER_URL = '/api/pleroma/friendships/approve' +const DENY_USER_URL = '/api/pleroma/friendships/deny' import { each, map } from 'lodash' import 'whatwg-fetch' @@ -127,11 +130,13 @@ const updateBanner = ({credentials, params}) => { const updateProfile = ({credentials, params}) => { let url = PROFILE_UPDATE_URL + console.log(params) + const form = new FormData() each(params, (value, key) => { - if (key === 'description' || /* Always include description, because it might be empty */ - value) { + /* Always include description and locked, because it might be empty or false */ + if (key === 'description' || key === 'locked' || value) { form.append(key, value) } }) @@ -216,6 +221,22 @@ const unblockUser = ({id, credentials}) => { }).then((data) => data.json()) } +const approveUser = ({id, credentials}) => { + let url = `${APPROVE_USER_URL}?user_id=${id}` + return fetch(url, { + headers: authHeaders(credentials), + method: 'POST' + }).then((data) => data.json()) +} + +const denyUser = ({id, credentials}) => { + let url = `${DENY_USER_URL}?user_id=${id}` + return fetch(url, { + headers: authHeaders(credentials), + method: 'POST' + }).then((data) => data.json()) +} + const fetchUser = ({id, credentials}) => { let url = `${USER_URL}?user_id=${id}` return fetch(url, { headers: authHeaders(credentials) }) @@ -240,6 +261,12 @@ const fetchAllFollowing = ({username, credentials}) => { .then((data) => data.json()) } +const fetchFollowRequests = ({credentials}) => { + const url = FOLLOW_REQUESTS_URL + return fetch(url, { headers: authHeaders(credentials) }) + .then((data) => data.json()) +} + const fetchConversation = ({id, credentials}) => { let url = `${CONVERSATION_URL}/${id}.json?count=100` return fetch(url, { headers: authHeaders(credentials) }) @@ -331,12 +358,14 @@ const retweet = ({ id, credentials }) => { }) } -const postStatus = ({credentials, status, mediaIds, inReplyToStatusId}) => { +const postStatus = ({credentials, status, spoilerText, visibility, mediaIds, inReplyToStatusId}) => { const idsText = mediaIds.join(',') const form = new FormData() form.append('status', status) form.append('source', 'Pleroma FE') + if (spoilerText) form.append('spoiler_text', spoilerText) + if (visibility) form.append('visibility', visibility) form.append('media_ids', idsText) if (inReplyToStatusId) { form.append('in_reply_to_status_id', inReplyToStatusId) @@ -440,7 +469,10 @@ const apiService = { externalProfile, followImport, deleteAccount, - changePassword + changePassword, + fetchFollowRequests, + approveUser, + denyUser } export default apiService diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 14173558..dbfb54f9 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -42,6 +42,14 @@ const backendInteractorService = (credentials) => { return apiService.unblockUser({credentials, id}) } + const approveUser = (id) => { + return apiService.approveUser({credentials, id}) + } + + const denyUser = (id) => { + return apiService.denyUser({credentials, id}) + } + const startFetching = ({timeline, store, userId = false}) => { return timelineFetcherService.startFetching({timeline, store, credentials, userId}) } @@ -51,6 +59,7 @@ const backendInteractorService = (credentials) => { } const fetchMutes = () => apiService.fetchMutes({credentials}) + const fetchFollowRequests = () => apiService.fetchFollowRequests({credentials}) const register = (params) => apiService.register(params) const updateAvatar = ({params}) => apiService.updateAvatar({credentials, params}) @@ -87,7 +96,10 @@ const backendInteractorService = (credentials) => { externalProfile, followImport, deleteAccount, - changePassword + changePassword, + fetchFollowRequests, + approveUser, + denyUser } return backendInteractorServiceInstance diff --git a/src/services/status_poster/status_poster.service.js b/src/services/status_poster/status_poster.service.js index 001ff8a5..3381e9e2 100644 --- a/src/services/status_poster/status_poster.service.js +++ b/src/services/status_poster/status_poster.service.js @@ -1,10 +1,10 @@ import { map } from 'lodash' import apiService from '../api/api.service.js' -const postStatus = ({ store, status, media = [], inReplyToStatusId = undefined }) => { +const postStatus = ({ store, status, spoilerText, visibility, media = [], inReplyToStatusId = undefined }) => { const mediaIds = map(media, 'id') - return apiService.postStatus({credentials: store.state.users.currentUser.credentials, status, mediaIds, inReplyToStatusId}) + return apiService.postStatus({credentials: store.state.users.currentUser.credentials, status, spoilerText, visibility, mediaIds, inReplyToStatusId}) .then((data) => data.json()) .then((data) => { if (!data.error) { |
