Commit 5d49edc8 authored by Shpuld Shpludson's avatar Shpuld Shpludson

Merge branch 'rc/2.0.5' into 'master'

Update MASTER for 2.0.5 patch

See merge request !1105
parents a0f780c4 0bc0a8d5
Pipeline #25701 passed with stages
in 9 minutes and 10 seconds
......@@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
- Removed the use of with_move parameters when fetching notifications
## [2.0.5] - 2020-05-12
### Add
- Added private notifications option for push notifications
- 'Copy link' button for statuses (in the ellipsis menu)
### Changed
- Registration page no longer requires email if the server is configured not to require it
### Fixed
- Status ellipsis menu closes properly when selecting certain options
## [2.0.3] - 2020-05-02
### Fixed
- Show more/less works correctly with auto-collapsed subjects and long posts
......
......@@ -241,6 +241,9 @@ const getNodeInfo = async ({ store }) => {
: federation.enabled
})
const accountActivationRequired = metadata.accountActivationRequired
store.dispatch('setInstanceOption', { name: 'accountActivationRequired', value: accountActivationRequired })
const accounts = metadata.staffAccounts
resolveStaffAccounts({ store, accounts })
} else {
......@@ -304,6 +307,9 @@ const afterStoreSetup = async ({ store, i18n }) => {
getNodeInfo({ store })
])
// Start fetching things that don't need to block the UI
store.dispatch('fetchMutes')
const router = new VueRouter({
mode: 'history',
routes: routes(store),
......
......@@ -3,7 +3,7 @@ import Popover from '../popover/popover.vue'
const AccountActions = {
props: [
'user'
'user', 'relationship'
],
data () {
return { }
......
......@@ -9,16 +9,16 @@
class="account-tools-popover"
>
<div class="dropdown-menu">
<template v-if="user.following">
<template v-if="relationship.following">
<button
v-if="user.showing_reblogs"
v-if="relationship.showing_reblogs"
class="btn btn-default dropdown-item"
@click="hideRepeats"
>
{{ $t('user_card.hide_repeats') }}
</button>
<button
v-if="!user.showing_reblogs"
v-if="!relationship.showing_reblogs"
class="btn btn-default dropdown-item"
@click="showRepeats"
>
......@@ -30,7 +30,7 @@
/>
</template>
<button
v-if="user.statusnet_blocking"
v-if="relationship.blocking"
class="btn btn-default btn-block dropdown-item"
@click="unblockUser"
>
......
......@@ -12,7 +12,7 @@
class="basic-user-card-expanded-content"
>
<UserCard
:user="user"
:user-id="user.id"
:rounded="true"
:bordered="true"
/>
......
......@@ -11,8 +11,11 @@ const BlockCard = {
user () {
return this.$store.getters.findUser(this.userId)
},
relationship () {
return this.$store.getters.relationship(this.userId)
},
blocked () {
return this.user.statusnet_blocking
return this.relationship.blocking
}
},
components: {
......
......@@ -29,6 +29,11 @@ const ExtraButtons = {
this.$store.dispatch('unmuteConversation', this.status.id)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
},
copyLink () {
navigator.clipboard.writeText(this.statusLink)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
}
},
computed: {
......@@ -46,6 +51,9 @@ const ExtraButtons = {
},
canMute () {
return !!this.currentUser
},
statusLink () {
return `${this.$store.state.instance.server}${this.$router.resolve({ name: 'conversation', params: { id: this.status.id } }).href}`
}
}
}
......
<template>
<Popover
v-if="canDelete || canMute || canPin"
trigger="click"
placement="top"
class="extra-button-popover"
>
<div slot="content">
<div
slot="content"
slot-scope="{close}"
>
<div class="dropdown-menu">
<button
v-if="canMute && !status.thread_muted"
......@@ -23,28 +25,35 @@
</button>
<button
v-if="!status.pinned && canPin"
v-close-popover
class="dropdown-item dropdown-item-icon"
@click.prevent="pinStatus"
@click="close"
>
<i class="icon-pin" /><span>{{ $t("status.pin") }}</span>
</button>
<button
v-if="status.pinned && canPin"
v-close-popover
class="dropdown-item dropdown-item-icon"
@click.prevent="unpinStatus"
@click="close"
>
<i class="icon-pin" /><span>{{ $t("status.unpin") }}</span>
</button>
<button
v-if="canDelete"
v-close-popover
class="dropdown-item dropdown-item-icon"
@click.prevent="deleteStatus"
@click="close"
>
<i class="icon-cancel" /><span>{{ $t("status.delete") }}</span>
</button>
<button
class="dropdown-item dropdown-item-icon"
@click.prevent="copyLink"
@click="close"
>
<i class="icon-share" /><span>{{ $t("status.copy_link") }}</span>
</button>
</div>
</div>
<i
......
import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate'
export default {
props: ['user', 'labelFollowing', 'buttonClass'],
props: ['relationship', 'labelFollowing', 'buttonClass'],
data () {
return {
inProgress: false
......@@ -8,12 +8,12 @@ export default {
},
computed: {
isPressed () {
return this.inProgress || this.user.following
return this.inProgress || this.relationship.following
},
title () {
if (this.inProgress || this.user.following) {
if (this.inProgress || this.relationship.following) {
return this.$t('user_card.follow_unfollow')
} else if (this.user.requested) {
} else if (this.relationship.requested) {
return this.$t('user_card.follow_again')
} else {
return this.$t('user_card.follow')
......@@ -22,9 +22,9 @@ export default {
label () {
if (this.inProgress) {
return this.$t('user_card.follow_progress')
} else if (this.user.following) {
} else if (this.relationship.following) {
return this.labelFollowing || this.$t('user_card.following')
} else if (this.user.requested) {
} else if (this.relationship.requested) {
return this.$t('user_card.follow_sent')
} else {
return this.$t('user_card.follow')
......@@ -33,20 +33,20 @@ export default {
},
methods: {
onClick () {
this.user.following ? this.unfollow() : this.follow()
this.relationship.following ? this.unfollow() : this.follow()
},
follow () {
this.inProgress = true
requestFollow(this.user, this.$store).then(() => {
requestFollow(this.relationship.id, this.$store).then(() => {
this.inProgress = false
})
},
unfollow () {
const store = this.$store
this.inProgress = true
requestUnfollow(this.user, store).then(() => {
requestUnfollow(this.relationship.id, store).then(() => {
this.inProgress = false
store.commit('removeStatus', { timeline: 'friends', userId: this.user.id })
store.commit('removeStatus', { timeline: 'friends', userId: this.relationship.id })
})
}
}
......
......@@ -18,6 +18,9 @@ const FollowCard = {
},
loggedIn () {
return this.$store.state.users.currentUser
},
relationship () {
return this.$store.getters.relationship(this.user.id)
}
}
}
......
......@@ -2,14 +2,14 @@
<basic-user-card :user="user">
<div class="follow-card-content-container">
<span
v-if="!noFollowsYou && user.follows_you"
v-if="!noFollowsYou && relationship.followed_by"
class="faint"
>
{{ isMe ? $t('user_card.its_you') : $t('user_card.follows_you') }}
</span>
<template v-if="!loggedIn">
<div
v-if="!user.following"
v-if="!relationship.following"
class="follow-card-follow-button"
>
<RemoteFollow :user="user" />
......@@ -17,9 +17,9 @@
</template>
<template v-else>
<FollowButton
:user="user"
class="follow-card-follow-button"
:relationship="relationship"
:label-following="$t('user_card.follow_unfollow')"
class="follow-card-follow-button"
/>
</template>
</div>
......
......@@ -11,8 +11,11 @@ const MuteCard = {
user () {
return this.$store.getters.findUser(this.userId)
},
relationship () {
return this.$store.getters.relationship(this.userId)
},
muted () {
return this.user.muted
return this.relationship.muting
}
},
components: {
......@@ -21,13 +24,13 @@ const MuteCard = {
methods: {
unmuteUser () {
this.progress = true
this.$store.dispatch('unmuteUser', this.user.id).then(() => {
this.$store.dispatch('unmuteUser', this.userId).then(() => {
this.progress = false
})
},
muteUser () {
this.progress = true
this.$store.dispatch('muteUser', this.user.id).then(() => {
this.$store.dispatch('muteUser', this.userId).then(() => {
this.progress = false
})
}
......
......@@ -75,7 +75,7 @@ const Notification = {
return this.generateUserProfileLink(this.targetUser)
},
needMute () {
return this.user.muted
return this.$store.getters.relationship(this.user.id).muting
},
isStatusNotification () {
return isStatusNotification(this.notification.type)
......
......@@ -40,7 +40,7 @@
<div class="notification-right">
<UserCard
v-if="userExpanded"
:user="getUser(notification)"
:user-id="getUser(notification).id"
:rounded="true"
:bordered="true"
/>
......
......@@ -2,7 +2,7 @@ import Popover from '../popover/popover.vue'
import { mapGetters } from 'vuex'
const ReactButton = {
props: ['status', 'loggedIn'],
props: ['status'],
data () {
return {
filterWord: ''
......
......@@ -37,7 +37,6 @@
</div>
</div>
<i
v-if="loggedIn"
slot="trigger"
class="icon-smile button-icon add-reaction-button"
:title="$t('tool_tip.add_reaction')"
......
import { validationMixin } from 'vuelidate'
import { required, sameAs } from 'vuelidate/lib/validators'
import { required, requiredIf, sameAs } from 'vuelidate/lib/validators'
import { mapActions, mapState } from 'vuex'
const registration = {
......@@ -14,15 +14,17 @@ const registration = {
},
captcha: {}
}),
validations: {
user: {
email: { required },
username: { required },
fullname: { required },
password: { required },
confirm: {
required,
sameAsPassword: sameAs('password')
validations () {
return {
user: {
email: { required: requiredIf(() => this.accountActivationRequired) },
username: { required },
fullname: { required },
password: { required },
confirm: {
required,
sameAsPassword: sameAs('password')
}
}
}
},
......@@ -43,7 +45,8 @@ const registration = {
signedIn: (state) => !!state.users.currentUser,
isPending: (state) => state.users.signUpPending,
serverValidationErrors: (state) => state.users.signUpErrors,
termsOfService: (state) => state.instance.tos
termsOfService: (state) => state.instance.tos,
accountActivationRequired: (state) => state.instance.accountActivationRequired
})
},
methods: {
......
......@@ -19,7 +19,7 @@
>
<UserCard
v-if="currentUser"
:user="currentUser"
:user-id="currentUser.id"
:hide-bio="true"
/>
<div
......
This diff is collapsed.
......@@ -94,7 +94,7 @@
<div class="status-body">
<UserCard
v-if="userExpanded"
:user="status.user"
:user-id="status.user.id"
:rounded="true"
:bordered="true"
class="status-usercard"
......@@ -226,118 +226,12 @@
</div>
</div>
<div
v-if="longSubject"
class="status-content-wrapper"
:class="{ 'tall-status': !showingLongSubject }"
>
<a
v-if="!showingLongSubject"
class="tall-status-hider"
:class="{ 'tall-status-hider_focused': isFocused }"
href="#"
@click.prevent="showingLongSubject=true"
>{{ $t("general.show_more") }}</a>
<div
class="status-content media-body"
@click.prevent="linkClicked"
v-html="contentHtml"
/>
<a
v-if="showingLongSubject"
href="#"
class="status-unhider"
@click.prevent="showingLongSubject=false"
>{{ $t("general.show_less") }}</a>
</div>
<div
v-else
:class="{'tall-status': hideTallStatus}"
class="status-content-wrapper"
>
<a
v-if="hideTallStatus"
class="tall-status-hider"
:class="{ 'tall-status-hider_focused': isFocused }"
href="#"
@click.prevent="toggleShowMore"
>{{ $t("general.show_more") }}</a>
<div
v-if="!hideSubjectStatus"
class="status-content media-body"
@click.prevent="linkClicked"
v-html="contentHtml"
/>
<div
v-else
class="status-content media-body"
@click.prevent="linkClicked"
v-html="status.summary_html"
/>
<a
v-if="hideSubjectStatus"
href="#"
class="cw-status-hider"
@click.prevent="toggleShowMore"
>
{{ $t("general.show_more") }}
<span
v-if="hasImageAttachments"
class="icon-picture"
/>
<span
v-if="hasVideoAttachments"
class="icon-video"
/>
<span
v-if="status.card"
class="icon-link"
/>
</a>
<a
v-if="showingMore"
href="#"
class="status-unhider"
@click.prevent="toggleShowMore"
>{{ $t("general.show_less") }}</a>
</div>
<div v-if="status.poll && status.poll.options">
<poll :base-poll="status.poll" />
</div>
<div
v-if="status.attachments && (!hideSubjectStatus || showingLongSubject)"
class="attachments media-body"
>
<attachment
v-for="attachment in nonGalleryAttachments"
:key="attachment.id"
class="non-gallery"
:size="attachmentSize"
:nsfw="nsfwClickthrough"
:attachment="attachment"
:allow-play="true"
:set-media="setMedia()"
/>
<gallery
v-if="galleryAttachments.length > 0"
:nsfw="nsfwClickthrough"
:attachments="galleryAttachments"
:set-media="setMedia()"
/>
</div>
<div
v-if="status.card && !hideSubjectStatus && !noHeading"
class="link-preview media-body"
>
<link-preview
:card="status.card"
:size="attachmentSize"
:nsfw="nsfwClickthrough"
/>
</div>
<StatusContent
:status="status"
:no-heading="noHeading"
:highlight="highlight"
:focused="isFocused"
/>
<transition name="fade">
<div
......@@ -404,7 +298,7 @@
:status="status"
/>
<ReactButton
:logged-in="loggedIn"
v-if="loggedIn"
:status="status"
/>
<extra-buttons
......@@ -630,105 +524,6 @@ $status-margin: 0.75em;
}
}
.tall-status {
position: relative;
height: 220px;
overflow-x: hidden;
overflow-y: hidden;
z-index: 1;
.status-content {
height: 100%;
mask: linear-gradient(to top, white, transparent) bottom/100% 70px no-repeat,
linear-gradient(to top, white, white);
/* Autoprefixed seem to ignore this one, and also syntax is different */
-webkit-mask-composite: xor;
mask-composite: exclude;
}
}
.tall-status-hider {
display: inline-block;
word-break: break-all;
position: absolute;
height: 70px;
margin-top: 150px;
width: 100%;
text-align: center;
line-height: 110px;
z-index: 2;
}
.status-unhider, .cw-status-hider {
width: 100%;
text-align: center;
display: inline-block;
word-break: break-all;
}
.status-content {
font-family: var(--postFont, sans-serif);
line-height: 1.4em;
white-space: pre-wrap;
a {
color: $fallback--link;
color: var(--postLink, $fallback--link);
}
img, video {
max-width: 100%;
max-height: 400px;
vertical-align: middle;
object-fit: contain;
&.emoji {
width: 32px;
height: 32px;
}
}
blockquote {
margin: 0.2em 0 0.2em 2em;
font-style: italic;
}
pre {
overflow: auto;
}
code, samp, kbd, var, pre {
font-family: var(--postCodeFont, monospace);
}
p {
margin: 0 0 1em 0;
}
p:last-child {
margin: 0 0 0 0;
}
h1 {
font-size: 1.1em;
line-height: 1.2em;
margin: 1.4em 0;
}
h2 {
font-size: 1.1em;