wip
This commit is contained in:
parent
f87ec61e96
commit
346c2959e0
|
@ -487,6 +487,9 @@ const endpoints: Endpoint[] = [
|
|||
{
|
||||
name: 'channels/show'
|
||||
},
|
||||
{
|
||||
name: 'channels/posts'
|
||||
},
|
||||
];
|
||||
|
||||
export default endpoints;
|
||||
|
|
79
src/api/endpoints/channels/posts.ts
Normal file
79
src/api/endpoints/channels/posts.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* Module dependencies
|
||||
*/
|
||||
import $ from 'cafy';
|
||||
import { default as Channel, IChannel } from '../../models/channel';
|
||||
import { default as Post, IPost } from '../../models/post';
|
||||
import serialize from '../../serializers/post';
|
||||
|
||||
/**
|
||||
* Show a posts of a channel
|
||||
*
|
||||
* @param {any} params
|
||||
* @param {any} user
|
||||
* @return {Promise<any>}
|
||||
*/
|
||||
module.exports = (params, user) => new Promise(async (res, rej) => {
|
||||
// Get 'limit' parameter
|
||||
const [limit = 1000, limitErr] = $(params.limit).optional.number().range(1, 1000).$;
|
||||
if (limitErr) return rej('invalid limit param');
|
||||
|
||||
// Get 'since_id' parameter
|
||||
const [sinceId, sinceIdErr] = $(params.since_id).optional.id().$;
|
||||
if (sinceIdErr) return rej('invalid since_id param');
|
||||
|
||||
// Get 'max_id' parameter
|
||||
const [maxId, maxIdErr] = $(params.max_id).optional.id().$;
|
||||
if (maxIdErr) return rej('invalid max_id param');
|
||||
|
||||
// Check if both of since_id and max_id is specified
|
||||
if (sinceId && maxId) {
|
||||
return rej('cannot set since_id and max_id');
|
||||
}
|
||||
|
||||
// Get 'channel_id' parameter
|
||||
const [channelId, channelIdErr] = $(params.channel_id).id().$;
|
||||
if (channelIdErr) return rej('invalid channel_id param');
|
||||
|
||||
// Fetch channel
|
||||
const channel: IChannel = await Channel.findOne({
|
||||
_id: channelId
|
||||
});
|
||||
|
||||
if (channel === null) {
|
||||
return rej('channel not found');
|
||||
}
|
||||
|
||||
//#region Construct query
|
||||
const sort = {
|
||||
_id: -1
|
||||
};
|
||||
|
||||
const query = {
|
||||
channel_id: channel._id
|
||||
} as any;
|
||||
|
||||
if (sinceId) {
|
||||
sort._id = 1;
|
||||
query._id = {
|
||||
$gt: sinceId
|
||||
};
|
||||
} else if (maxId) {
|
||||
query._id = {
|
||||
$lt: maxId
|
||||
};
|
||||
}
|
||||
//#endregion Construct query
|
||||
|
||||
// Issue query
|
||||
const posts = await Post
|
||||
.find(query, {
|
||||
limit: limit,
|
||||
sort: sort
|
||||
});
|
||||
|
||||
// Serialize
|
||||
res(await Promise.all(posts.map(async (post) =>
|
||||
await serialize(post, user)
|
||||
)));
|
||||
});
|
14
src/web/app/common/scripts/channel-stream.js
Normal file
14
src/web/app/common/scripts/channel-stream.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
import Stream from './stream';
|
||||
|
||||
/**
|
||||
* Channel stream connection
|
||||
*/
|
||||
class Connection extends Stream {
|
||||
constructor() {
|
||||
super('channel');
|
||||
}
|
||||
}
|
||||
|
||||
export default Connection;
|
|
@ -2,6 +2,8 @@
|
|||
<mk-ui ref="ui">
|
||||
<main if={ !parent.fetching }>
|
||||
<h1>{ parent.channel.title }</h1>
|
||||
<mk-channel-post each={ parent.posts } post={ this }/>
|
||||
<mk-channel-form channel={ parent.channel }/>
|
||||
</main>
|
||||
</mk-ui>
|
||||
<style>
|
||||
|
@ -14,12 +16,15 @@
|
|||
</style>
|
||||
<script>
|
||||
import Progress from '../../../common/scripts/loading';
|
||||
import ChannelStream from '../../../common/scripts/channel-stream';
|
||||
|
||||
this.mixin('api');
|
||||
|
||||
this.id = this.opts.id;
|
||||
this.fetching = true;
|
||||
this.channel = null;
|
||||
this.posts = null;
|
||||
this.connection = new ChannelStream();
|
||||
|
||||
this.on('mount', () => {
|
||||
document.documentElement.style.background = '#efefef';
|
||||
|
@ -38,6 +43,88 @@
|
|||
|
||||
document.title = channel.title + ' | Misskey'
|
||||
});
|
||||
|
||||
this.api('channels/posts', {
|
||||
channel_id: this.id
|
||||
}).then(posts => {
|
||||
this.update({
|
||||
posts: posts
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</mk-channel-page>
|
||||
|
||||
<mk-channel-post>
|
||||
<header>
|
||||
<b>{ post.user.name }</b>
|
||||
</header>
|
||||
<div>
|
||||
{ post.text }
|
||||
</div>
|
||||
<style>
|
||||
:scope
|
||||
display block
|
||||
margin 0
|
||||
padding 0
|
||||
|
||||
> header
|
||||
> b
|
||||
color #008000
|
||||
|
||||
</style>
|
||||
<script>
|
||||
this.post = this.opts.post;
|
||||
</script>
|
||||
</mk-channel-post>
|
||||
|
||||
<mk-channel-form>
|
||||
<p if={ reply }>{ reply.user.name }への返信: (or <a onclick={ clearReply }>キャンセル</a>)</p>
|
||||
<textarea ref="text" disabled={ wait }></textarea>
|
||||
<button class={ wait: wait } ref="submit" disabled={ wait || (refs.text.value.length == 0) } onclick={ post }>
|
||||
{ wait ? 'やってます' : 'やる' }<mk-ellipsis if={ wait }/>
|
||||
</button>
|
||||
|
||||
<style>
|
||||
:scope
|
||||
display block
|
||||
|
||||
</style>
|
||||
<script>
|
||||
this.mixin('api');
|
||||
|
||||
this.channel = this.opts.channel;
|
||||
|
||||
this.clearReply = () => {
|
||||
this.update({
|
||||
reply: null
|
||||
});
|
||||
};
|
||||
|
||||
this.clear = () => {
|
||||
this.clearReply();
|
||||
this.refs.text.value = '';
|
||||
};
|
||||
|
||||
this.post = e => {
|
||||
this.update({
|
||||
wait: true
|
||||
});
|
||||
|
||||
this.api('posts/create', {
|
||||
text: this.refs.text.value,
|
||||
reply_to_id: this.reply ? this.reply.id : undefined,
|
||||
channel_id: this.channel.id
|
||||
}).then(data => {
|
||||
this.clear();
|
||||
}).catch(err => {
|
||||
alert('失敗した');
|
||||
}).then(() => {
|
||||
this.update({
|
||||
wait: false
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
</script>
|
||||
</mk-channel-form>
|
||||
|
|
44
src/web/app/desktop/tags/pages/drive-chooser.tag
Normal file
44
src/web/app/desktop/tags/pages/drive-chooser.tag
Normal file
|
@ -0,0 +1,44 @@
|
|||
<mk-drive-chooser>
|
||||
<mk-drive-browser ref="browser" multiple={ parent.multiple }/>
|
||||
<div>
|
||||
<button class="upload" title="PCからドライブにファイルをアップロード" onclick={ upload }><i class="fa fa-upload"></i></button>
|
||||
<button class="cancel" onclick={ close }>キャンセル</button>
|
||||
<button class="ok" onclick={ parent.ok }>決定</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:scope
|
||||
display block
|
||||
height 100%
|
||||
|
||||
</style>
|
||||
<script>
|
||||
this.multiple = this.opts.multiple != null ? this.opts.multiple : false;
|
||||
|
||||
this.on('mount', () => {
|
||||
this.refs.browser.on('selected', file => {
|
||||
this.files = [file];
|
||||
this.ok();
|
||||
});
|
||||
|
||||
this.refs.browser.on('change-selection', files => {
|
||||
this.update({
|
||||
files: files
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.upload = () => {
|
||||
this.refs.browser.selectLocalFile();
|
||||
};
|
||||
|
||||
this.close = () => {
|
||||
window.close();
|
||||
};
|
||||
|
||||
this.ok = () => {
|
||||
window.opener.cb(this.multiple ? this.files : this.files[0]);
|
||||
window.close();
|
||||
};
|
||||
</script>
|
||||
</mk-drive-chooser>
|
Loading…
Reference in a new issue