kopia lustrzana https://github.com/nextcloud/social
commit
38a6dad1a2
|
@ -31,8 +31,8 @@ return [
|
|||
['name' => 'SocialPub#displayPost', 'url' => '/@{username}/{postId}', 'verb' => 'GET'],
|
||||
|
||||
['name' => 'Local#newPost', 'url' => '/api/v1/post', 'verb' => 'POST'],
|
||||
['name' => 'Local#timeline', 'url' => '/api/v1/timeline', 'verb' => 'PUT'],
|
||||
['name' => 'Local#direct', 'url' => '/api/v1/direct', 'verb' => 'PUT'],
|
||||
['name' => 'Local#timeline', 'url' => '/api/v1/timeline', 'verb' => 'GET'],
|
||||
['name' => 'Local#direct', 'url' => '/api/v1/direct', 'verb' => 'PUT']
|
||||
['name' => 'Local#accountSearch', 'url' => '/api/v1/accounts/search', 'verb' => 'GET'],
|
||||
['name' => 'Local#actorInfo', 'url' => '/api/v1/actor/info', 'verb' => 'GET']
|
||||
|
||||
|
|
|
@ -144,12 +144,12 @@ class LocalController extends Controller {
|
|||
*
|
||||
* @return DataResponse
|
||||
*/
|
||||
public function timeline(): DataResponse {
|
||||
public function timeline($since = 0, $limit = 5): DataResponse {
|
||||
|
||||
// $this->miscService->log('timeline: ' . json_encode($data));
|
||||
|
||||
try {
|
||||
$posts = $this->noteService->getTimeline();
|
||||
$posts = $this->noteService->getTimeline((int)$since, (int)$limit);
|
||||
|
||||
return $this->success($posts);
|
||||
} catch (Exception $e) {
|
||||
|
|
|
@ -109,6 +109,26 @@ class ActorsRequest extends ActorsRequestBuilder {
|
|||
return $this->parseActorsSelectSql($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $username
|
||||
* @return Person
|
||||
* @throws ActorDoesNotExistException
|
||||
*/
|
||||
public function getFromId(string $id): Person {
|
||||
$qb = $this->getActorsSelectSql();
|
||||
$this->limitToIdString($qb, $id);
|
||||
|
||||
$cursor = $qb->execute();
|
||||
$data = $cursor->fetch();
|
||||
$cursor->closeCursor();
|
||||
|
||||
if ($data === false) {
|
||||
throw new ActorDoesNotExistException('Actor not found');
|
||||
}
|
||||
|
||||
return $this->parseActorsSelectSql($data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return Actor from database, based on the userId of the owner.
|
||||
|
|
|
@ -224,7 +224,23 @@ class CoreRequestBuilder {
|
|||
|
||||
/**
|
||||
* @param IQueryBuilder $qb
|
||||
* @param string $field
|
||||
* @param string $recipient
|
||||
*/
|
||||
protected function limitPaginate(IQueryBuilder &$qb, int $since = 0, int $limit = 5) {
|
||||
if ($since > 0) {
|
||||
$expr = $qb->expr();
|
||||
$dt = new \DateTime();
|
||||
$dt->setTimestamp($since);
|
||||
// TODO: Pagination should use published date, once we can properly query the db for that
|
||||
$qb->andWhere($expr->lt('creation', $qb->createNamedParameter($dt, IQueryBuilder::PARAM_DATE), IQueryBuilder::PARAM_DATE));
|
||||
}
|
||||
$qb->setMaxResults($limit);
|
||||
$qb->orderBy('creation', 'desc');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IQueryBuilder $qb
|
||||
* @param string $field"
|
||||
* @param string|integer|array $values
|
||||
*/
|
||||
private function limitToDBField(IQueryBuilder &$qb, $field, $values) {
|
||||
|
|
|
@ -34,6 +34,7 @@ use OCA\Social\Model\ActivityPub\Note;
|
|||
use OCA\Social\Service\ActivityService;
|
||||
use OCA\Social\Service\ConfigService;
|
||||
use OCA\Social\Service\MiscService;
|
||||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
class NotesRequest extends NotesRequestBuilder {
|
||||
|
@ -86,8 +87,8 @@ class NotesRequest extends NotesRequestBuilder {
|
|||
->setValue('summary', $qb->createNamedParameter($note->getSummary()))
|
||||
->setValue('published', $qb->createNamedParameter($note->getPublished()))
|
||||
->setValue('attributed_to', $qb->createNamedParameter($note->getAttributedTo()))
|
||||
->setValue('in_reply_to', $qb->createNamedParameter($note->getInReplyTo()));
|
||||
|
||||
->setValue('in_reply_to', $qb->createNamedParameter($note->getInReplyTo()))
|
||||
->setValue('creation', $qb->createNamedParameter(new \DateTime('now'), IQueryBuilder::PARAM_DATE));
|
||||
$qb->execute();
|
||||
|
||||
return $qb->getLastInsertId();
|
||||
|
@ -102,9 +103,10 @@ class NotesRequest extends NotesRequestBuilder {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPublicNotes(): array {
|
||||
public function getPublicNotes($since = 0, $limit = 5): array {
|
||||
$qb = $this->getNotesSelectSql();
|
||||
$this->limitToRecipient($qb, ActivityService::TO_PUBLIC);
|
||||
$this->limitPaginate($qb, $since, $limit);
|
||||
|
||||
$notes = [];
|
||||
$cursor = $qb->execute();
|
||||
|
|
|
@ -236,8 +236,17 @@ class NoteService implements ICoreService {
|
|||
*
|
||||
* @return Note[]
|
||||
*/
|
||||
public function getTimeline(): array {
|
||||
return $this->notesRequest->getPublicNotes();
|
||||
public function getTimeline($since = 0, $limit = 5): array {
|
||||
$notes = $this->notesRequest->getPublicNotes($since, $limit);
|
||||
$result = [];
|
||||
/** @var Note $note */
|
||||
foreach ($notes as $note) {
|
||||
$actor = $this->actorService->getActorById($note->getAttributedTo());
|
||||
$noteEnhanced = $note->jsonSerialize();
|
||||
$noteEnhanced['actor'] = $actor->jsonSerialize();
|
||||
$result[] = $noteEnhanced;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -90,6 +90,12 @@ class ActorService {
|
|||
return $actor;
|
||||
}
|
||||
|
||||
public function getActorById(string $id): Person {
|
||||
$actor = $this->actorsRequest->getFromId($id);
|
||||
|
||||
return $actor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $userId
|
||||
|
|
|
@ -12857,6 +12857,11 @@
|
|||
"integrity": "sha512-AA86yKZ5uOKz87/q1UpngEXhbRkaYg1b7HMMVRobNV1IVKqZe8oLIzo6iMocVwZXnYitlGwf2k4ZRLOZlS8oPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"vue-infinite-loading": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-infinite-loading/-/vue-infinite-loading-2.4.1.tgz",
|
||||
"integrity": "sha512-HAAZmoLfowJQJgsRgFn12RkN5RohShnUw/zT+O9OXQc7S0cjmbIuP3xq7md2JhpawVUsemjnPoz8xqLtchPHIQ=="
|
||||
},
|
||||
"vue-jest": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-jest/-/vue-jest-2.6.0.tgz",
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
"uuid": "^3.3.2",
|
||||
"vue": "^2.5.16",
|
||||
"vue-click-outside": "^1.0.7",
|
||||
"vue-infinite-loading": "^2.4.1",
|
||||
"vue-router": "^3.0.1",
|
||||
"vuex": "^3.0.1",
|
||||
"vuex-router-sync": "^5.0.0"
|
||||
|
|
25
src/App.vue
25
src/App.vue
|
@ -115,31 +115,6 @@ export default {
|
|||
if (serverDataElmt !== null) {
|
||||
this.$store.commit('setServerData', JSON.parse(document.getElementById('serverData').dataset.server))
|
||||
}
|
||||
|
||||
let example = {
|
||||
message: 'Want to #DropDropbox? #DeleteGoogle? #decentralize? We got you covered, easy as a piece of 🥞\n'
|
||||
+ '\n'
|
||||
+ 'Get started right now: https://nextcloud.com/signup',
|
||||
author: 'Nextcloud 📱☁️💻',
|
||||
authorId: '@nextcloud@mastodon.xyz',
|
||||
authorAvatar: OC.linkTo('social', 'img/nextcloud.png'),
|
||||
timestamp: '1 day ago'
|
||||
}
|
||||
let data = []
|
||||
for (let i = 0; i < 3; i++) {
|
||||
example.id = Math.floor((Math.random() * 100))
|
||||
data.push(example)
|
||||
}
|
||||
data.push({
|
||||
message: 'Want to #DropDropbox? #DeleteGoogle? #decentralize? We got you covered, easy as a piece of 🥞\n'
|
||||
+ '\n'
|
||||
+ 'Get started right now: https://nextcloud.com/signup',
|
||||
author: 'Admin☁️💻',
|
||||
authorId: 'admin',
|
||||
authorAvatar: OC.linkTo('social', 'img/nextcloud.png'),
|
||||
timestamp: '1 day ago'
|
||||
})
|
||||
this.$store.commit('addToTimeline', data)
|
||||
},
|
||||
methods: {
|
||||
hideInfo() {
|
||||
|
|
|
@ -20,12 +20,17 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import axios from 'nextcloud-axios'
|
||||
|
||||
|
||||
const state = {
|
||||
timeline: []
|
||||
timeline: [],
|
||||
since: new Date(),
|
||||
}
|
||||
const mutations = {
|
||||
addToTimeline(state, data) {
|
||||
for (let item in data) {
|
||||
state.since = data[item].published;
|
||||
state.timeline.push(data[item])
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +40,19 @@ const getters = {
|
|||
return state.timeline
|
||||
}
|
||||
}
|
||||
const actions = {}
|
||||
const actions = {
|
||||
post(context, post) {
|
||||
axios.post(OC.generateUrl('apps/social/api/v1/post')).then((response) => {
|
||||
context.commit('addPost', { uid: uid, data: response.data })
|
||||
})
|
||||
},
|
||||
fetchTimeline(context, account) {
|
||||
const sinceTimestamp = Date.parse(state.since)/1000;
|
||||
return axios.get(OC.generateUrl('apps/social/api/v1/timeline?limit=5&since=' + sinceTimestamp)).then((response) => {
|
||||
context.commit('addToTimeline', response.data.result);
|
||||
return response.data.result;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default { state, mutations, getters, actions }
|
||||
|
|
|
@ -25,7 +25,21 @@
|
|||
<div class="submitLoading icon-loading-small hidden" />
|
||||
</form>
|
||||
</div>
|
||||
<timeline-entry v-for="entry in timeline" :item="entry" :key="entry.id" />
|
||||
<!--<timeline-entry v-for="entry in timeline" :item="entry" :key="entry.id" /> //-->
|
||||
<div v-for="entry in timeline">
|
||||
{{entry.content}}
|
||||
<pre style="height: 200px; overflow:scroll;">{{entry}}</pre>
|
||||
</div>
|
||||
<infinite-loading @infinite="infiniteHandler" ref="infiniteLoading">
|
||||
<div slot="spinner"><div class="icon-loading"></div></div>
|
||||
<div slot="no-more"><div class="list-end"></div></div>
|
||||
<div slot="no-results">
|
||||
<div id="emptycontent">
|
||||
<div class="icon-social"></div>
|
||||
<h2>{{t('social', 'No posts found.')}}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</infinite-loading>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -124,12 +138,14 @@ import {
|
|||
Multiselect,
|
||||
Avatar
|
||||
} from 'nextcloud-vue'
|
||||
import InfiniteLoading from 'vue-infinite-loading'
|
||||
import TimelineEntry from './../components/TimelineEntry'
|
||||
|
||||
export default {
|
||||
name: 'Timeline',
|
||||
components: {
|
||||
PopoverMenu, AppNavigation, TimelineEntry, Multiselect, Avatar
|
||||
PopoverMenu, AppNavigation, TimelineEntry, Multiselect, Avatar,
|
||||
InfiniteLoading
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
|
@ -198,27 +214,17 @@ export default {
|
|||
}
|
||||
},
|
||||
beforeMount: function() {
|
||||
let example = {
|
||||
message: 'Want to #DropDropbox? #DeleteGoogle? #decentralize? We got you covered, easy as a piece of 🥞\n'
|
||||
+ '\n'
|
||||
+ 'Get started right now: https://nextcloud.com/signup',
|
||||
author: 'Nextcloud 📱☁️💻',
|
||||
authorId: '@nextcloud@mastodon.xyz',
|
||||
authorAvatar: OC.linkTo('social', 'img/nextcloud.png'),
|
||||
timestamp: '1 day ago'
|
||||
}
|
||||
let data = []
|
||||
for (let i = 0; i < 20; i++) {
|
||||
let item = Object.assign({}, example)
|
||||
item.id = i
|
||||
data.push(item)
|
||||
}
|
||||
this.$store.commit('addToTimeline', data)
|
||||
|
||||
},
|
||||
methods: {
|
||||
hideInfo() {
|
||||
this.infoHidden = true
|
||||
}
|
||||
},
|
||||
infiniteHandler($state) {
|
||||
this.$store.dispatch('fetchTimeline', {
|
||||
account: this.currentUser.uid
|
||||
}).then((response) => { response.length > 0 ? $state.loaded() : $state.complete() });
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
Ładowanie…
Reference in New Issue