From 543604fd2d107d3c6b7123e5713ac923eb76f23c Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 14 May 2019 22:38:16 +0300 Subject: removed unused masto api, added initial version of interactions timeline --- src/boot/routes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/boot/routes.js') diff --git a/src/boot/routes.js b/src/boot/routes.js index 7e54a98b..508c76df 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -3,7 +3,7 @@ import PublicAndExternalTimeline from 'components/public_and_external_timeline/p import FriendsTimeline from 'components/friends_timeline/friends_timeline.vue' import TagTimeline from 'components/tag_timeline/tag_timeline.vue' import ConversationPage from 'components/conversation-page/conversation-page.vue' -import Mentions from 'components/mentions/mentions.vue' +import Interactions from 'components/interactions/interactions.vue' import DMs from 'components/dm_timeline/dm_timeline.vue' import UserProfile from 'components/user_profile/user_profile.vue' import Settings from 'components/settings/settings.vue' @@ -34,7 +34,7 @@ export default (store) => { { name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline }, { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, { name: 'external-user-profile', path: '/users/:id', component: UserProfile }, - { name: 'mentions', path: '/users/:username/mentions', component: Mentions }, + { name: 'mentions', path: '/users/:username/interactions', component: Interactions }, { name: 'dms', path: '/users/:username/dms', component: DMs }, { name: 'settings', path: '/settings', component: Settings }, { name: 'registration', path: '/registration', component: Registration }, -- cgit v1.2.3-70-g09d2 From 7976d118ca60143b25d111c24a45eff1d083fd9b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 15 May 2019 20:44:35 +0300 Subject: Cleanup, little documentation, localization --- src/boot/routes.js | 2 +- src/components/interactions/interactions.vue | 6 +++--- src/components/nav_panel/nav_panel.vue | 2 +- src/components/notifications/notifications.js | 12 +++++++++--- src/components/notifications/notifications.scss | 6 ++++-- src/components/notifications/notifications.vue | 6 ++++-- src/components/side_drawer/side_drawer.vue | 5 +++++ src/i18n/en.json | 6 ++++++ src/i18n/ru.json | 6 ++++++ 9 files changed, 39 insertions(+), 12 deletions(-) (limited to 'src/boot/routes.js') diff --git a/src/boot/routes.js b/src/boot/routes.js index 508c76df..1a179099 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -34,7 +34,7 @@ export default (store) => { { name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline }, { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, { name: 'external-user-profile', path: '/users/:id', component: UserProfile }, - { name: 'mentions', path: '/users/:username/interactions', component: Interactions }, + { name: 'interactions', path: '/users/:username/interactions', component: Interactions }, { name: 'dms', path: '/users/:username/dms', component: DMs }, { name: 'settings', path: '/settings', component: Settings }, { name: 'registration', path: '/registration', component: Registration }, diff --git a/src/components/interactions/interactions.vue b/src/components/interactions/interactions.vue index 751e5d40..5a204ca7 100644 --- a/src/components/interactions/interactions.vue +++ b/src/components/interactions/interactions.vue @@ -9,9 +9,9 @@ ref="tabSwitcher" :onSwitch="onModeSwitch" > - - - + + +
  • - + {{ $t("nav.interactions") }}
  • diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index acc31986..3a6e3b94 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -7,9 +7,15 @@ import { } from '../../services/notification_utils/notification_utils.js' const Notifications = { - props: [ - 'noHeading', 'minimalMode', 'filterMode' - ], + props: { + // Disables display of panel header + noHeading: Boolean, + // Disables panel styles, unread mark, potentially other notification-related actions + // meant for "Interactions" timeline + minimalMode: Boolean, + // Custom filter mode, an array of strings, possible values 'mention', 'repeat', 'like', 'follow', used to override global filter for use in "Interactions" timeline + filterMode: Array + }, data () { return { bottomedOut: false diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index c0b458cc..622d12f4 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -1,8 +1,10 @@ @import '../../_variables.scss'; .notifications { - // a bit of a hack to allow scrolling below notifications - padding-bottom: 15em; + &:not(.minimal) { + // a bit of a hack to allow scrolling below notifications + padding-bottom: 15em; + } .loadmore-error { color: $fallback--text; diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index 3c3ae191..c71499b2 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -1,5 +1,5 @@
    ({ + user: { + email: '' + }, + isPending: false, + success: false, + throttled: false, + error: null + }), + computed: { + ...mapState({ + signedIn: (state) => !!state.users.currentUser, + instance: state => state.instance + }), + mailerEnabled () { + return this.instance.mailerEnabled + } + }, + created () { + if (this.signedIn) { + this.$router.push({ name: 'root' }) + } + }, + methods: { + dismissError () { + this.error = null + }, + submit () { + this.isPending = true + const email = this.user.email + const instance = this.instance.server + + passwordResetApi({ instance, email }).then(({ status }) => { + this.isPending = false + this.user.email = '' + + if (status === 204) { + this.success = true + this.error = null + } else if (status === 404 || status === 400) { + this.error = this.$t('password_reset.not_found') + this.$nextTick(() => { + this.$refs.email.focus() + }) + } else if (status === 429) { + this.throttled = true + this.error = this.$t('password_reset.too_many_requests') + } + }).catch(() => { + this.isPending = false + this.user.email = '' + this.error = this.$t('general.generic_error') + }) + } + } +} + +export default passwordReset diff --git a/src/components/password_reset/password_reset.vue b/src/components/password_reset/password_reset.vue new file mode 100644 index 00000000..00474e95 --- /dev/null +++ b/src/components/password_reset/password_reset.vue @@ -0,0 +1,116 @@ + + + + diff --git a/src/i18n/en.json b/src/i18n/en.json index 6a9af55c..ddde471a 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -608,5 +608,16 @@ "person_talking": "{count} person talking", "people_talking": "{count} people talking", "no_results": "No results" + }, + "password_reset": { + "forgot_password": "Forgot password?", + "password_reset": "Password reset", + "instruction": "Enter your email address or username. We will send you a link to reset your password.", + "placeholder": "Your email or username", + "check_email": "Check your email for a link to reset your password.", + "return_home": "Return to the home page", + "not_found": "We couldn't find that email or username.", + "too_many_requests": "You have reached the limit of attempts, try again later.", + "password_reset_disabled": "Password reset is disabled. Please contact your instance administrator." } } diff --git a/src/i18n/ru.json b/src/i18n/ru.json index 90ed6664..3af65f40 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -389,5 +389,16 @@ "person_talking": "Популярно у {count} человека", "people_talking": "Популярно у {count} человек", "no_results": "Ничего не найдено" + }, + "password_reset": { + "forgot_password": "Забыли пароль?", + "password_reset": "Сброс пароля", + "instruction": "Введите ваш email или имя пользователя, и мы отправим вам ссылку для сброса пароля.", + "placeholder": "Ваш email или имя пользователя", + "check_email": "Проверьте ваш email и перейдите по ссылке для сброса пароля.", + "return_home": "Вернуться на главную страницу", + "not_found": "Мы не смогли найти аккаунт с таким email-ом или именем пользователя.", + "too_many_requests": "Вы исчерпали допустимое количество попыток, попробуйте позже.", + "password_reset_disabled": "Сброс пароля отключен. Cвяжитесь с администратором вашего сервера." } } diff --git a/src/services/new_api/password_reset.js b/src/services/new_api/password_reset.js new file mode 100644 index 00000000..43199625 --- /dev/null +++ b/src/services/new_api/password_reset.js @@ -0,0 +1,18 @@ +import { reduce } from 'lodash' + +const MASTODON_PASSWORD_RESET_URL = `/auth/password` + +const resetPassword = ({ instance, email }) => { + const params = { email } + const query = reduce(params, (acc, v, k) => { + const encoded = `${k}=${encodeURIComponent(v)}` + return `${acc}&${encoded}` + }, '') + const url = `${instance}${MASTODON_PASSWORD_RESET_URL}?${query}` + + return window.fetch(url, { + method: 'POST' + }) +} + +export default resetPassword -- cgit v1.2.3-70-g09d2 From 37be781312c6e3139a7b158835a51b141fd94e70 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 16 Oct 2019 10:00:26 +0000 Subject: Require password reset --- src/boot/routes.js | 2 +- src/components/login_form/login_form.js | 2 ++ src/components/password_reset/password_reset.js | 6 ++++++ src/components/password_reset/password_reset.vue | 16 +++++++++++++++- src/i18n/en.json | 4 +++- 5 files changed, 27 insertions(+), 3 deletions(-) (limited to 'src/boot/routes.js') diff --git a/src/boot/routes.js b/src/boot/routes.js index cd02711c..5670236c 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -47,7 +47,7 @@ export default (store) => { { name: 'dms', path: '/users/:username/dms', component: DMs, beforeEnter: validateAuthenticatedRoute }, { name: 'settings', path: '/settings', component: Settings }, { name: 'registration', path: '/registration', component: Registration }, - { name: 'password-reset', path: '/password-reset', component: PasswordReset }, + { name: 'password-reset', path: '/password-reset', component: PasswordReset, props: true }, { name: 'registration-token', path: '/registration/:token', component: Registration }, { name: 'friend-requests', path: '/friend-requests', component: FollowRequests, beforeEnter: validateAuthenticatedRoute }, { name: 'user-settings', path: '/user-settings', component: UserSettings, beforeEnter: validateAuthenticatedRoute }, diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js index 10f52fe2..0b574a04 100644 --- a/src/components/login_form/login_form.js +++ b/src/components/login_form/login_form.js @@ -59,6 +59,8 @@ const LoginForm = { if (result.error) { if (result.error === 'mfa_required') { this.requireMFA({ app: app, settings: result }) + } else if (result.identifier === 'password_reset_required') { + this.$router.push({ name: 'password-reset', params: { passwordResetRequested: true } }) } else { this.error = result.error this.focusOnPasswordInput() diff --git a/src/components/password_reset/password_reset.js b/src/components/password_reset/password_reset.js index fa71e07a..62e74e30 100644 --- a/src/components/password_reset/password_reset.js +++ b/src/components/password_reset/password_reset.js @@ -25,6 +25,12 @@ const passwordReset = { this.$router.push({ name: 'root' }) } }, + props: { + passwordResetRequested: { + default: false, + type: Boolean + } + }, methods: { dismissError () { this.error = null diff --git a/src/components/password_reset/password_reset.vue b/src/components/password_reset/password_reset.vue index 00474e95..713c9dce 100644 --- a/src/components/password_reset/password_reset.vue +++ b/src/components/password_reset/password_reset.vue @@ -10,7 +10,10 @@ >
    -

    +

    + {{ $t('password_reset.password_reset_required_but_mailer_is_disabled') }} +

    +

    {{ $t('password_reset.password_reset_disabled') }}

    @@ -25,6 +28,12 @@
    +

    + {{ $t('password_reset.password_reset_required') }} +

    {{ $t('password_reset.instruction') }}

    @@ -104,6 +113,11 @@ margin: 0.3em 0.0em 1em; } + .password-reset-required { + background-color: var(--alertError, $fallback--alertError); + padding: 10px 0; + } + .notice-dismissible { padding-right: 2rem; } diff --git a/src/i18n/en.json b/src/i18n/en.json index b58112e3..d11b2d14 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -632,6 +632,8 @@ "return_home": "Return to the home page", "not_found": "We couldn't find that email or username.", "too_many_requests": "You have reached the limit of attempts, try again later.", - "password_reset_disabled": "Password reset is disabled. Please contact your instance administrator." + "password_reset_disabled": "Password reset is disabled. Please contact your instance administrator.", + "password_reset_required": "You must reset your password to log in.", + "password_reset_required_but_mailer_is_disabled": "You must reset your password, but password reset is disabled. Please contact your instance administrator." } } -- cgit v1.2.3-70-g09d2 From e4820012a3573ad02846d254fedb0cfa36582fdf Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Fri, 8 Nov 2019 22:27:25 +0000 Subject: redirect /remote-users/:username@:hostname -> /users/:id, /remote-users/:hostname/:username -> /users/:id --- src/boot/routes.js | 11 ++++++++ .../remote_user_resolver/remote_user_resolver.js | 31 ++++++++++++++++++++++ .../remote_user_resolver/remote_user_resolver.vue | 20 ++++++++++++++ src/i18n/en.json | 5 ++++ 4 files changed, 67 insertions(+) create mode 100644 src/components/remote_user_resolver/remote_user_resolver.js create mode 100644 src/components/remote_user_resolver/remote_user_resolver.vue (limited to 'src/boot/routes.js') diff --git a/src/boot/routes.js b/src/boot/routes.js index 5670236c..7400a682 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -18,6 +18,7 @@ import AuthForm from 'components/auth_form/auth_form.js' import ChatPanel from 'components/chat_panel/chat_panel.vue' import WhoToFollow from 'components/who_to_follow/who_to_follow.vue' import About from 'components/about/about.vue' +import RemoteUserResolver from 'components/remote_user_resolver/remote_user_resolver.vue' export default (store) => { const validateAuthenticatedRoute = (to, from, next) => { @@ -42,6 +43,16 @@ export default (store) => { { name: 'friends', path: '/main/friends', component: FriendsTimeline, beforeEnter: validateAuthenticatedRoute }, { name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline }, { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, + { name: 'remote-user-profile-acct', + path: '/remote-users/(@?):username([^/@]+)@:hostname([^/@]+)', + component: RemoteUserResolver, + beforeEnter: validateAuthenticatedRoute + }, + { name: 'remote-user-profile', + path: '/remote-users/:hostname/:username', + component: RemoteUserResolver, + beforeEnter: validateAuthenticatedRoute + }, { name: 'external-user-profile', path: '/users/:id', component: UserProfile }, { name: 'interactions', path: '/users/:username/interactions', component: Interactions, beforeEnter: validateAuthenticatedRoute }, { name: 'dms', path: '/users/:username/dms', component: DMs, beforeEnter: validateAuthenticatedRoute }, diff --git a/src/components/remote_user_resolver/remote_user_resolver.js b/src/components/remote_user_resolver/remote_user_resolver.js new file mode 100644 index 00000000..9b5e511e --- /dev/null +++ b/src/components/remote_user_resolver/remote_user_resolver.js @@ -0,0 +1,31 @@ +const RemoteUserResolver = { + data: () => ({ + error: false + }), + mounted () { + this.redirect() + }, + methods: { + redirect () { + const acct = this.$route.params.username + '@' + this.$route.params.hostname + this.$store.state.api.backendInteractor.fetchUser({ id: acct }) + .then((externalUser) => { + if (externalUser.error) { + this.error = true + } else { + this.$store.commit('addNewUsers', [externalUser]) + const id = externalUser.id + this.$router.replace({ + name: 'external-user-profile', + params: { id } + }) + } + }) + .catch(() => { + this.error = true + }) + } + } +} + +export default RemoteUserResolver diff --git a/src/components/remote_user_resolver/remote_user_resolver.vue b/src/components/remote_user_resolver/remote_user_resolver.vue new file mode 100644 index 00000000..f8945225 --- /dev/null +++ b/src/components/remote_user_resolver/remote_user_resolver.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/src/i18n/en.json b/src/i18n/en.json index 8ecb3f3d..483432ff 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -172,6 +172,11 @@ "password_confirmation_match": "should be the same as password" } }, + "remote_user_resolver": { + "remote_user_resolver": "Remote user resolver", + "searching_for": "Searching for", + "error": "Not found." + }, "selectable_list": { "select_all": "Select all" }, -- cgit v1.2.3-70-g09d2