kopia lustrzana https://github.com/nextcloud/social
Merge remote-tracking branch 'origin/more-for-local-accounts' into more-for-local-accounts
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>pull/82/head
commit
75447af767
|
@ -5,7 +5,7 @@
|
||||||
Mockup:
|
Mockup:
|
||||||

|

|
||||||
|
|
||||||
- **🙋 Find your friends:** No matter if they use Nextcloud, [Mastodon](https://en.wikipedia.org/wiki/Mastodon_(software)), [Friendica](https://en.wikipedia.org/wiki/Friendica), [GNU social](https://en.wikipedia.org/wiki/GNU_social) or others – you can follow them!
|
- **🙋 Find your friends:** No matter if they use Nextcloud, [🐘 Mastodon](https://joinmastodon.org), [🇫 Friendica](https://friendi.ca), and soon [✱ diaspora*](https://joindiaspora.com), [👹 MediaGoblin](https://www.mediagoblin.org) and more – you can follow them!
|
||||||
- **📜 Profile info:** No need to fill out more profiles – your info from Nextcloud will be used and extended.
|
- **📜 Profile info:** No need to fill out more profiles – your info from Nextcloud will be used and extended.
|
||||||
- **👐 Own your posts:** Everything you post stays on your Nextcloud!
|
- **👐 Own your posts:** Everything you post stays on your Nextcloud!
|
||||||
- **🕸 Open standards:** We use the [ActivityPub](https://en.wikipedia.org/wiki/ActivityPub) standard!
|
- **🕸 Open standards:** We use the [ActivityPub](https://en.wikipedia.org/wiki/ActivityPub) standard!
|
||||||
|
@ -13,8 +13,8 @@ Mockup:
|
||||||
|
|
||||||
## Development setup
|
## Development setup
|
||||||
|
|
||||||
1. ☁ Clone this into your `apps` folder of your Nextcloud
|
1. ☁ Clone this into the `apps` folder of your Nextcloud: `git clone https://github.com/nextcloud-gmbh/social.git`
|
||||||
2. 👩💻 In a terminal, run the command `make dev-setup` to install the dependencies
|
2. 👩💻 Run `make dev-setup` to install the dependencies
|
||||||
3. 🏗 Then to build the Javascript whenever you make changes, run `make build-js`
|
3. 🏗 Then to build the Javascript whenever you make changes, run `make build-js`
|
||||||
4. ✅ Enable the app through the app management of your Nextcloud
|
4. ✅ Enable the app through the app management of your Nextcloud
|
||||||
5. 🎉 Partytime!
|
5. 🎉 Partytime!
|
||||||
|
|
|
@ -45,6 +45,7 @@ use OCA\Social\Service\ActorService;
|
||||||
use OCA\Social\Service\ConfigService;
|
use OCA\Social\Service\ConfigService;
|
||||||
use OCA\Social\Service\MiscService;
|
use OCA\Social\Service\MiscService;
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
|
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||||
use OCP\AppFramework\Http\DataResponse;
|
use OCP\AppFramework\Http\DataResponse;
|
||||||
use OCP\AppFramework\Http\FileDisplayResponse;
|
use OCP\AppFramework\Http\FileDisplayResponse;
|
||||||
use OCP\AppFramework\Http\RedirectResponse;
|
use OCP\AppFramework\Http\RedirectResponse;
|
||||||
|
@ -186,7 +187,11 @@ class NavigationController extends Controller {
|
||||||
// neither.
|
// neither.
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TemplateResponse(Application::APP_NAME, 'main', $data);
|
$csp = new ContentSecurityPolicy();
|
||||||
|
$csp->addAllowedImageDomain('*');
|
||||||
|
$response = new TemplateResponse(Application::APP_NAME, 'main', $data);
|
||||||
|
$response->setContentSecurityPolicy($csp);
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -201,6 +201,32 @@ class CacheActorsRequest extends CacheActorsRequestBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get Cached version of a local Actor, based on the preferred username
|
||||||
|
*
|
||||||
|
* @param string $account
|
||||||
|
*
|
||||||
|
* @return Person
|
||||||
|
* @throws CacheActorDoesNotExistException
|
||||||
|
*/
|
||||||
|
public function getFromLocalAccount(string $account): Person {
|
||||||
|
$qb = $this->getCacheActorsSelectSql();
|
||||||
|
$this->limitToPreferredUsername($qb, $account);
|
||||||
|
$this->limitToLocal($qb, true);
|
||||||
|
$this->leftJoinCacheDocuments($qb, 'icon_id');
|
||||||
|
|
||||||
|
$cursor = $qb->execute();
|
||||||
|
$data = $cursor->fetch();
|
||||||
|
$cursor->closeCursor();
|
||||||
|
|
||||||
|
if ($data === false) {
|
||||||
|
throw new CacheActorDoesNotExistException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->parseCacheActorsSelectSql($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $search
|
* @param string $search
|
||||||
* @param string $viewerId
|
* @param string $viewerId
|
||||||
|
|
|
@ -108,6 +108,22 @@ class FollowsRequestBuilder extends CoreRequestBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base of the Sql Select request for Shares
|
||||||
|
*
|
||||||
|
* @return IQueryBuilder
|
||||||
|
*/
|
||||||
|
protected function countFollowsSelectSql(): IQueryBuilder {
|
||||||
|
$qb = $this->dbConnection->getQueryBuilder();
|
||||||
|
$qb->selectAlias($qb->createFunction('COUNT(*)'), 'count')
|
||||||
|
->from(self::TABLE_SERVER_FOLLOWS, 'f');
|
||||||
|
|
||||||
|
$this->defaultSelectAlias = 'f';
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base of the Sql Delete request
|
* Base of the Sql Delete request
|
||||||
*
|
*
|
||||||
|
|
|
@ -7631,9 +7631,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nextcloud-vue": {
|
"nextcloud-vue": {
|
||||||
"version": "0.4.2",
|
"version": "0.4.6",
|
||||||
"resolved": "https://registry.npmjs.org/nextcloud-vue/-/nextcloud-vue-0.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/nextcloud-vue/-/nextcloud-vue-0.4.6.tgz",
|
||||||
"integrity": "sha512-4aePhl0VqpJw9LqNsQenPFmQ6I715vbOAlfVjPMdqVqoKnN9r2gr87/PfNeOLkVFrfo0vaYPx4QS0JSiLsAiqg==",
|
"integrity": "sha512-INrIz3RmxxUCrM/xy2ytLvrrZr131p0DOT87A+IH0/+LFlfK//eR0uB32lSUsqh9Tb+bkTyu8Ztq9iuTrFfl2Q==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/polyfill": "^7.0.0",
|
"@babel/polyfill": "^7.0.0",
|
||||||
"md5": "^2.2.1",
|
"md5": "^2.2.1",
|
||||||
|
@ -8239,9 +8239,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"popper.js": {
|
"popper.js": {
|
||||||
"version": "1.14.5",
|
"version": "1.14.6",
|
||||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.6.tgz",
|
||||||
"integrity": "sha512-fs4Sd8bZLgEzrk8aS7Em1qh+wcawtE87kRUJQhK6+LndyV1HerX7+LURzAylVaTyWIn5NTB/lyjnWqw/AZ6Yrw=="
|
"integrity": "sha512-AGwHGQBKumlk/MDfrSOf0JHhJCImdDMcGNoqKmKkU+68GFazv3CQ6q9r7Ja1sKDZmYWTckY/uLyEznheTDycnA=="
|
||||||
},
|
},
|
||||||
"posix-character-classes": {
|
"posix-character-classes": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
|
|
|
@ -30,10 +30,11 @@
|
||||||
"@babel/polyfill": "^7.0.0",
|
"@babel/polyfill": "^7.0.0",
|
||||||
"linkifyjs": "^2.1.7",
|
"linkifyjs": "^2.1.7",
|
||||||
"nextcloud-axios": "^0.1.2",
|
"nextcloud-axios": "^0.1.2",
|
||||||
"nextcloud-vue": "^0.4.2",
|
"nextcloud-vue": "^0.4.6",
|
||||||
"tributejs": "^3.3.5",
|
"tributejs": "^3.3.5",
|
||||||
"twemoji": "^11.2.0",
|
"twemoji": "^11.2.0",
|
||||||
"uuid": "^3.3.2",
|
"uuid": "^3.3.2",
|
||||||
|
"v-tooltip": "^2.0.0-rc.33",
|
||||||
"vue": "^2.5.16",
|
"vue": "^2.5.16",
|
||||||
"vue-click-outside": "^1.0.7",
|
"vue-click-outside": "^1.0.7",
|
||||||
"vue-contenteditable-directive": "^1.2.0",
|
"vue-contenteditable-directive": "^1.2.0",
|
||||||
|
|
14
src/App.vue
14
src/App.vue
|
@ -63,6 +63,7 @@ import axios from 'nextcloud-axios'
|
||||||
import TimelineEntry from './components/TimelineEntry'
|
import TimelineEntry from './components/TimelineEntry'
|
||||||
import ProfileInfo from './components/ProfileInfo'
|
import ProfileInfo from './components/ProfileInfo'
|
||||||
import Search from './components/Search'
|
import Search from './components/Search'
|
||||||
|
import currentuserMixin from './mixins/currentUserMixin'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
@ -75,6 +76,7 @@ export default {
|
||||||
ProfileInfo,
|
ProfileInfo,
|
||||||
Search
|
Search
|
||||||
},
|
},
|
||||||
|
mixins: [currentuserMixin],
|
||||||
data: function() {
|
data: function() {
|
||||||
return {
|
return {
|
||||||
infoHidden: false,
|
infoHidden: false,
|
||||||
|
@ -84,21 +86,9 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
url: function() {
|
|
||||||
return OC.linkTo('social', 'img/nextcloud.png')
|
|
||||||
},
|
|
||||||
currentUser: function() {
|
|
||||||
return OC.getCurrentUser()
|
|
||||||
},
|
|
||||||
socialId: function() {
|
|
||||||
return '@' + OC.getCurrentUser().uid + '@' + OC.getHost()
|
|
||||||
},
|
|
||||||
timeline: function() {
|
timeline: function() {
|
||||||
return this.$store.getters.getTimeline
|
return this.$store.getters.getTimeline
|
||||||
},
|
},
|
||||||
serverData: function() {
|
|
||||||
return this.$store.getters.getServerData
|
|
||||||
},
|
|
||||||
menu: function() {
|
menu: function() {
|
||||||
let defaultCategories = [
|
let defaultCategories = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
<form class="new-post-form" @submit.prevent="createPost">
|
<form class="new-post-form" @submit.prevent="createPost">
|
||||||
<div class="author currentUser">
|
<div class="author currentUser">
|
||||||
{{ currentUser.displayName }}
|
{{ currentUser.displayName }}
|
||||||
|
|
||||||
<span class="social-id">{{ socialId }}</span>
|
<span class="social-id">{{ socialId }}</span>
|
||||||
</div>
|
</div>
|
||||||
<vue-tribute :options="tributeOptions">
|
<vue-tribute :options="tributeOptions">
|
||||||
|
@ -385,29 +384,42 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
activeState() {
|
||||||
|
return (type) => {
|
||||||
|
if (type === this.type) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
visibilityPopover() {
|
visibilityPopover() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
action: () => { this.switchType('direct') },
|
action: () => { this.switchType('direct') },
|
||||||
icon: this.visibilityIconClass('direct'),
|
icon: this.visibilityIconClass('direct'),
|
||||||
|
active: this.activeState('direct'),
|
||||||
text: t('social', 'Direct'),
|
text: t('social', 'Direct'),
|
||||||
longtext: t('social', 'Post to mentioned users only')
|
longtext: t('social', 'Post to mentioned users only')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
action: () => { this.switchType('unlisted') },
|
action: () => { this.switchType('unlisted') },
|
||||||
icon: this.visibilityIconClass('unlisted'),
|
icon: this.visibilityIconClass('unlisted'),
|
||||||
|
active: this.activeState('unlisted'),
|
||||||
text: t('social', 'Unlisted'),
|
text: t('social', 'Unlisted'),
|
||||||
longtext: t('social', 'Do not post to public timelines')
|
longtext: t('social', 'Do not post to public timelines')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
action: () => { this.switchType('followers') },
|
action: () => { this.switchType('followers') },
|
||||||
icon: this.visibilityIconClass('followers'),
|
icon: this.visibilityIconClass('followers'),
|
||||||
|
active: this.activeState('followers'),
|
||||||
text: t('social', 'Followers'),
|
text: t('social', 'Followers'),
|
||||||
longtext: t('social', 'Post to followers only')
|
longtext: t('social', 'Post to followers only')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
action: () => { this.switchType('public') },
|
action: () => { this.switchType('public') },
|
||||||
icon: this.visibilityIconClass('public'),
|
icon: this.visibilityIconClass('public'),
|
||||||
|
active: this.activeState('public'),
|
||||||
text: t('social', 'Public'),
|
text: t('social', 'Public'),
|
||||||
longtext: t('social', 'Post to public timelines')
|
longtext: t('social', 'Post to public timelines')
|
||||||
}
|
}
|
||||||
|
@ -434,7 +446,7 @@ export default {
|
||||||
emoji.replaceWith(em)
|
emoji.replaceWith(em)
|
||||||
})
|
})
|
||||||
let to = []
|
let to = []
|
||||||
const re = /@((\w+)(@[\w.]+)?)/g
|
const re = /@(([\w-_.]+)(@[\w-.]+)?)/g
|
||||||
let match = null
|
let match = null
|
||||||
do {
|
do {
|
||||||
match = re.exec(element.innerText)
|
match = re.exec(element.innerText)
|
||||||
|
|
|
@ -81,12 +81,14 @@
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { Avatar } from 'nextcloud-vue'
|
import { Avatar } from 'nextcloud-vue'
|
||||||
|
import serverData from '../mixins/serverData'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProfileInfo',
|
name: 'ProfileInfo',
|
||||||
components: {
|
components: {
|
||||||
Avatar
|
Avatar
|
||||||
},
|
},
|
||||||
|
mixins: [serverData],
|
||||||
props: {
|
props: {
|
||||||
uid: {
|
uid: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -98,17 +100,12 @@ export default {
|
||||||
if (typeof this.accountInfo.displayname !== 'undefined') { return this.accountInfo.displayname.value || '' }
|
if (typeof this.accountInfo.displayname !== 'undefined') { return this.accountInfo.displayname.value || '' }
|
||||||
return this.uid
|
return this.uid
|
||||||
},
|
},
|
||||||
serverData: function() {
|
|
||||||
return this.$store.getters.getServerData
|
|
||||||
},
|
|
||||||
accountInfo: function() {
|
accountInfo: function() {
|
||||||
return this.$store.getters.getAccount(this.uid)
|
return this.$store.getters.getAccount(this.uid)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
follow() {
|
|
||||||
// TODO: implement following users
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,15 +22,13 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="social__wrapper">
|
<div class="social__wrapper">
|
||||||
<div v-if="results.length < 1" id="emptycontent" :class="{'icon-loading': loading}"
|
<div v-if="results.length < 1" id="emptycontent" :class="{'icon-loading': loading}">
|
||||||
class="">
|
<div v-if="!loading" class="icon-search" />
|
||||||
<div class="icon-search" />
|
<h2 v-if="!loading">{{ t('social', 'No accounts found') }}</h2>
|
||||||
<h2>{{ t('social', 'No accounts found') }}</h2>
|
<p v-if="!loading">No accounts found for {{ term }}</p>
|
||||||
<p>No accounts found for {{ term }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="match || results.length > 0">
|
<div v-if="match || results.length > 0">
|
||||||
<h3>{{ t('social', 'Search') }} {{ term }}</h3>
|
<h3>{{ t('social', 'Search') }} {{ term }}</h3>
|
||||||
<UserEntry :item="match" />
|
|
||||||
<UserEntry v-for="result in results" :key="result.id" :item="result" />
|
<UserEntry v-for="result in results" :key="result.id" :item="result" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -65,20 +63,32 @@ export default {
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
term(val) {
|
term(val) {
|
||||||
|
// TODO: debounce
|
||||||
|
this.search(val)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
this.search(this.term)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
search(val) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.accountSearch(val).then((response) => {
|
|
||||||
this.results = response.data.result.accounts
|
|
||||||
this.loading = false
|
|
||||||
})
|
|
||||||
const re = /@((\w+)(@[\w.]+)?)/g
|
const re = /@((\w+)(@[\w.]+)?)/g
|
||||||
if (val.match(re)) {
|
if (val.match(re)) {
|
||||||
this.remoteSearch(val).then((response) => {
|
this.remoteSearch(val).then((response) => {
|
||||||
this.match = response.data.result.account
|
this.match = response.data.result.account
|
||||||
|
this.accountSearch(val).then((response) => {
|
||||||
|
this.results = response.data.result.accounts
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
}).catch((e) => { this.match = null })
|
}).catch((e) => { this.match = null })
|
||||||
|
} else {
|
||||||
|
this.accountSearch(val).then((response) => {
|
||||||
|
this.results = response.data.result.accounts
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
accountSearch(term) {
|
accountSearch(term) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
return axios.get(OC.generateUrl('apps/social/api/v1/accounts/search?search=' + term))
|
return axios.get(OC.generateUrl('apps/social/api/v1/accounts/search?search=' + term))
|
||||||
|
|
|
@ -21,40 +21,47 @@
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="user-entry">
|
<div v-if="item" class="user-entry">
|
||||||
<div class="entry-content">
|
<div class="entry-content">
|
||||||
<div class="user-avatar">
|
<div class="user-avatar">
|
||||||
<avatar v-if="item.local" :size="32" :user="item.preferredUsername" />
|
<avatar v-if="item.local" :size="32" :user="item.preferredUsername" />
|
||||||
<avatar v-else url="" />
|
<avatar v-else :url="item.icon.url" />
|
||||||
</div>
|
</div>
|
||||||
<div class="user-details">
|
<div class="user-details">
|
||||||
<router-link v-if="item.local" :to="{ name: 'profile', params: { account: item.account }}">
|
<router-link v-if="item.local" :to="{ name: 'profile', params: { account: item.account }}">
|
||||||
<span class="post-author">{{ item.preferredUsername }}</span>
|
<span class="post-author">{{ item.preferredUsername }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
<a v-else :href="item.id" target="_blank"
|
<a v-else :href="item.id" target="_blank"
|
||||||
rel="noreferrer">{{ item.preferredUsername }}</a>
|
rel="noreferrer">{{ item.name }} <span class="user-description">{{ item.account }}</span></a>
|
||||||
<p class="user-description">{{ item.account }}</p>
|
<!-- TODO check where the html is coming from to avoid security issues -->
|
||||||
|
<p v-html="item.summary" />
|
||||||
</div>
|
</div>
|
||||||
<button v-if="item.following" class="icon-checkmark-color">Following</button>
|
<button class="icon-checkmark-color" @click="unfollow()"
|
||||||
<button v-else class="primary">Follow</button>
|
@mouseover="followingText=t('social', 'Unfollow')"
|
||||||
|
@mouseleave="followingText=t('social', 'Following')">{{ followingText }}</button>
|
||||||
|
<button class="primary" @click="follow">Follow</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Avatar } from 'nextcloud-vue'
|
import { Avatar } from 'nextcloud-vue'
|
||||||
|
import follow from '../mixins/follow'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'UserEntry',
|
name: 'UserEntry',
|
||||||
components: {
|
components: {
|
||||||
Avatar
|
Avatar
|
||||||
},
|
},
|
||||||
|
mixins: [
|
||||||
|
follow
|
||||||
|
],
|
||||||
props: {
|
props: {
|
||||||
item: { type: Object, default: () => {} }
|
item: { type: Object, default: () => {} }
|
||||||
},
|
},
|
||||||
data: function() {
|
data: function() {
|
||||||
return {
|
return {
|
||||||
|
followingText: t('social', 'Following')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,19 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import serverData from './serverData'
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [
|
||||||
|
serverData
|
||||||
|
],
|
||||||
computed: {
|
computed: {
|
||||||
currentUser: function() {
|
currentUser: function() {
|
||||||
return OC.getCurrentUser()
|
return OC.getCurrentUser()
|
||||||
},
|
},
|
||||||
socialId: function() {
|
socialId: function() {
|
||||||
return '@' + OC.getCurrentUser().uid + '@' + OC.getHost()
|
const url = document.createElement('a')
|
||||||
|
url.setAttribute('href', this.serverData.cloudAddress)
|
||||||
|
return '@' + OC.getCurrentUser().uid + '@' + url.hostname
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
|
||||||
|
*
|
||||||
|
* @author Julius Härtl <jus@bitgrid.net>
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import axios from 'nextcloud-axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
follow() {
|
||||||
|
return axios.put(OC.generateUrl('/apps/social/api/v1/account/follow?account=' + this.item.account))
|
||||||
|
},
|
||||||
|
unfollow() {
|
||||||
|
return axios.delete(OC.generateUrl('/apps/social/api/v1/account/follow?account=' + this.item.account))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
|
||||||
|
*
|
||||||
|
* @author Julius Härtl <jus@bitgrid.net>
|
||||||
|
*
|
||||||
|
* @license GNU AGPL version 3 or any later version
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
serverData: function() {
|
||||||
|
return this.$store.getters.getServerData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Ładowanie…
Reference in New Issue