Compare commits
114 Commits
Author | SHA1 | Date | |
---|---|---|---|
91f1c3a10a | |||
8fc1e07136 | |||
a62e2b83ff | |||
e31a2f7e55 | |||
1598e996b1 | |||
4fb7ee760a | |||
37865cb381 | |||
ab8b882435 | |||
1b2996947e | |||
ea56d368e3 | |||
dbd3a750f5 | |||
f41818141f | |||
d2f576accd | |||
4e483856d4 | |||
2997f26e3c | |||
cdab596240 | |||
fca7a9da94 | |||
8ba178f795 | |||
d98c67e13c | |||
d129151fdf | |||
1b9c69f793 | |||
42dd092334 | |||
8dc9ec06f8 | |||
ae5da782e5 | |||
313b0cec65 | |||
12a51972ed | |||
a2f3b2966f | |||
0c2627f08b | |||
9535df12dd | |||
2400471a0d | |||
784da8c37b | |||
3778f9c521 | |||
e1cec85f1e | |||
ca9c087060 | |||
5b2d91baad | |||
08e099b88d | |||
4153b0db38 | |||
88701a21bb | |||
3ddc73ca94 | |||
693d793265 | |||
5d685233dd | |||
16575751d9 | |||
1f6295f437 | |||
6737fe2ead | |||
4e77939fca | |||
21f528c07d | |||
23f835fac0 | |||
f21343225c | |||
f13a59f7db | |||
0315b9274c | |||
da88043962 | |||
0352bf0cc2 | |||
baa71070a8 | |||
2713064f27 | |||
f6387ac115 | |||
d704aca035 | |||
2b54b4ac06 | |||
7410f2f4c0 | |||
99c3c1258a | |||
e51184931d | |||
3bc9a40b48 | |||
9f49ca8fdb | |||
550d1547b4 | |||
ca0b56ee57 | |||
ef1d854f2c | |||
a5023271ef | |||
c3747db670 | |||
fe1e60a28c | |||
f91d2e8c8d | |||
dccc2c60e3 | |||
933e25804c | |||
0b503661af | |||
58082431ff | |||
2536bfb5f5 | |||
6428066552 | |||
4bf3827b73 | |||
3cad494404 | |||
ef0793311f | |||
6f3e341e89 | |||
2fea3be7c0 | |||
82059d4fd9 | |||
07ddeae2f1 | |||
f2279758b2 | |||
1ed189a518 | |||
137741d307 | |||
d702f6e090 | |||
f33701233c | |||
70003269e5 | |||
61896d2386 | |||
52d640c5a7 | |||
c65f5761e1 | |||
3016ac4805 | |||
28a47cd331 | |||
6ecb88b0d1 | |||
8df1278c8e | |||
52bec430d4 | |||
da4cec8767 | |||
ad0087d7dd | |||
9630860035 | |||
75e4c8d74d | |||
1a5ee81e7e | |||
3476be16ab | |||
c42f61a0f4 | |||
b42a9e1c4e | |||
4495525705 | |||
a603602f32 | |||
67b28f9b6e | |||
fd947407af | |||
30444e5f1a | |||
f0d818de24 | |||
ae0284b1b1 | |||
166c4ebda0 | |||
319eed029b | |||
ec5aa10167 |
86
.autogen/autogen.sh
Executable file
86
.autogen/autogen.sh
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# BEARER_TOKEN=
|
||||||
|
# CAMPAIGN_ID=
|
||||||
|
# GITHUB_TOKEN=
|
||||||
|
# HEAD='acid-chicken:patch-autogen'
|
||||||
|
# REPO='syuilo/misskey'
|
||||||
|
test "$(curl -LSs -w '\n' -- "https://api.github.com/repos/$REPO/pulls?access_token=$GITHUB_TOKEN" | jq -r '.[].head.label' | grep $HEAD)" && exit 1
|
||||||
|
cd "$(dirname $0)/.." && \
|
||||||
|
touch null.cache && \
|
||||||
|
rm *.cache && \
|
||||||
|
git checkout master && \
|
||||||
|
git pull origin master && \
|
||||||
|
git pull upstream master && \
|
||||||
|
git stash && \
|
||||||
|
git rebase -f upstream/master && \
|
||||||
|
git branch patch-autogen && \
|
||||||
|
git checkout patch-autogen && \
|
||||||
|
git reset --hard HEAD || \
|
||||||
|
exit 1
|
||||||
|
touch patreon.md.cache && \
|
||||||
|
rm patreon.md.cache && \
|
||||||
|
echo '<!-- PATREON_START -->' > patreon.md.cache && \
|
||||||
|
URL="https://www.patreon.com/api/oauth2/v2/campaigns/$CAMPAIGN_ID/members?include=currently_entitled_tiers,user&fields%5Btier%5D=title&fields%5Buser%5D=full_name,thumb_url,url,hide_pledges"
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
touch patreon.raw.cache && \
|
||||||
|
rm patreon.raw.cache && \
|
||||||
|
curl -LSs -w '\n' -H "Authorization: Bearer $BEARER_TOKEN" -- $URL > patreon.raw.cache && \
|
||||||
|
touch patreon.cache && \
|
||||||
|
rm patreon.cache && \
|
||||||
|
cat patreon.raw.cache | \
|
||||||
|
jq -r '(.data|map(select(.relationships.currently_entitled_tiers.data[]))|map(.relationships.user.data.id))as$data|.included|map(select(.attributes.hide_pledges==false))|map(select(.id as$id|$data|contains([$id])))|map(.attributes|[.full_name,.thumb_url,.url]|@tsv)|.[]|@text' >> patreon.cache && \
|
||||||
|
echo '<table><tr>' >> patreon.md.cache && \
|
||||||
|
cat patreon.cache | \
|
||||||
|
awk -F'\t' '{print $2,$1}' | \
|
||||||
|
sed -e 's/ /\\" alt=\\"/' | \
|
||||||
|
xargs -I% echo '<td><img src="%"></td>' >> patreon.md.cache && \
|
||||||
|
echo '</tr><tr>' >> patreon.md.cache && \
|
||||||
|
cat patreon.cache | \
|
||||||
|
awk -F'\t' '{print $3,$1}' | \
|
||||||
|
sed -e 's/ /\\">/' | \
|
||||||
|
xargs -I% echo '<td><a href="%</a></td>' >> patreon.md.cache && \
|
||||||
|
echo '</tr></table>' >> patreon.md.cache || \
|
||||||
|
exit 1
|
||||||
|
NEW_URL="$(cat patreon.raw.cache | jq -r '.links.next')"
|
||||||
|
test "$NEW_URL" = 'null' && \
|
||||||
|
break || \
|
||||||
|
URL="$NEW_URL"
|
||||||
|
done
|
||||||
|
IGNORE= && \
|
||||||
|
echo -e "\n**Last updated:** $(date -uR | sed 's/\+0000/UTC/')\n<!-- PATREON_END -->" >> patreon.md.cache && \
|
||||||
|
touch README.md && \
|
||||||
|
touch .autogen/README.md && \
|
||||||
|
rm .autogen/README.md && \
|
||||||
|
mv README.md .autogen/README.md && \
|
||||||
|
cat .autogen/README.md | while IFS= read LINE;
|
||||||
|
do
|
||||||
|
if [[ -z "$IGNORE" ]]
|
||||||
|
then
|
||||||
|
if [[ "$LINE" = '<!-- PATREON_START -->' ]]
|
||||||
|
then
|
||||||
|
IGNORE='PATREON_INSIDE'
|
||||||
|
else
|
||||||
|
echo "$LINE" >> README.md
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ "$LINE" = '<!-- PATREON_END -->' ]]
|
||||||
|
then
|
||||||
|
IGNORE=
|
||||||
|
cat patreon.md.cache >> README.md
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
cat patreon.md.cache
|
||||||
|
touch null.cache && \
|
||||||
|
rm *.cache && \
|
||||||
|
diff .autogen/README.md README.md > diff.cache
|
||||||
|
cat diff.cache && \
|
||||||
|
test 4 -lt $(cat diff.cache | wc -l) && \
|
||||||
|
git add README.md && \
|
||||||
|
git commit -m 'Update README.md [AUTOGEN]' && \
|
||||||
|
git push -f origin patch-autogen && \
|
||||||
|
curl -LSs -w '\n' -X POST -d '{"title":"[AUTOMATED] Update README.md","body":"*This pull request was created by a tool.*","head":"'$HEAD'","base":"master"}' -- "https://api.github.com/repos/$REPO/pulls?access_token=$GITHUB_TOKEN"
|
||||||
|
git stash
|
||||||
|
git checkout master
|
||||||
|
git branch -D patch-autogen
|
16
README.md
16
README.md
@ -55,35 +55,41 @@ Misskey is using Crowdin for l10n.
|
|||||||
<table><tr>
|
<table><tr>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12378075/0156f769e20f412594fa6b87d85fe228/1?token-time=2145916800&token-hash=IsIJRUXszzoD6-7pDnRY8I05T9nSznc4GTaxj7C9SwU%3D" alt="39ff"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12378075/0156f769e20f412594fa6b87d85fe228/1?token-time=2145916800&token-hash=IsIJRUXszzoD6-7pDnRY8I05T9nSznc4GTaxj7C9SwU%3D" alt="39ff"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12731202/0995c46cdcb54153ab5f073f5869b70a/1?token-time=2145916800&token-hash=Yd60FK_SWfQO56SeiJpy1tDHOnCV4xdEywQe8gn5_Wo%3D" alt="negao"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12731202/0995c46cdcb54153ab5f073f5869b70a/1?token-time=2145916800&token-hash=Yd60FK_SWfQO56SeiJpy1tDHOnCV4xdEywQe8gn5_Wo%3D" alt="negao"></td>
|
||||||
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13099460/43cecdbaa63a40d79bf50a96b9910b9d/1?token-time=2145916800&token-hash=d6P5MWHHsCMxUuBAEPAoVc5wLUR19mIhqAq7Ma9h9rI%3D" alt="ne_moni"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/1?token-time=2145916800&token-hash=f03BFb4S2FUx9YEt87TnEmifb4h33OywGBW2akQVtQY%3D" alt="Melilot"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12913507/f7181eacafe8469a93033d85f5969c29/1?token-time=2145916800&token-hash=f03BFb4S2FUx9YEt87TnEmifb4h33OywGBW2akQVtQY%3D" alt="Melilot"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/3384329/8b713330cb27404ea6e9fac50ff96efe/1?token-time=2145916800&token-hash=0eu4-m1gTWA9PhptVZt6rdKcusqcD7RB87rJT23VVFI%3D" alt="べすれい"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12021162/963128bb8d14476dbd8407943db8f31a/1?token-time=2145916800&token-hash=GgJ_NmUB6_nnRNLVGUWjV-WX91On7BOu59LKncYV9fE%3D" alt="gutfuckllc"></td>
|
||||||
<td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td>
|
<td><img src="https://c8.patreon.com/2/100/12718187" alt="Peter G."></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/2?token-time=2145916800&token-hash=zElv7ZcPL3viGsXbNG_KWiKrbV0vvw1gk0panx8DJoo%3D" alt="Naoki Kosaka"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13039004/509d0c412eb14ae08d6a812a3054f7d6/1?token-time=2145916800&token-hash=zwSu01tOtn5xTUucDZHuPsCxF2HBEMVs9ROJKTlEV_o%3D" alt="nemu"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12931605/ead494101f364dffa90efe49e36fb494/1?token-time=2145916800&token-hash=NzSFPjIlodXyv41rwK61aZWVZWfI4surJaNj8vWKvqM%3D" alt="Reiju"></td>
|
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td><a href="https://www.patreon.com/user?u=12378075">39ff</a></td>
|
<td><a href="https://www.patreon.com/user?u=12378075">39ff</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=12731202">negao</a></td>
|
<td><a href="https://www.patreon.com/user?u=12731202">negao</a></td>
|
||||||
|
<td><a href="https://www.patreon.com/user?u=13099460">ne_moni</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td>
|
<td><a href="https://www.patreon.com/user?u=12913507">Melilot</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td>
|
<td><a href="https://www.patreon.com/user?u=3384329">べすれい</a></td>
|
||||||
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
|
<td><a href="https://www.patreon.com/gutfuckllc">gutfuckllc</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td>
|
<td><a href="https://www.patreon.com/user?u=12718187">Peter G.</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=5881381">Naoki Kosaka</a></td>
|
<td><a href="https://www.patreon.com/user?u=13039004">nemu</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=12931605">Reiju</a></td>
|
|
||||||
</tr></table>
|
</tr></table>
|
||||||
<table><tr>
|
<table><tr>
|
||||||
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/5881381/6235ca5d3fb04c8e95ef5b4ff2abcc18/2?token-time=2145916800&token-hash=zElv7ZcPL3viGsXbNG_KWiKrbV0vvw1gk0panx8DJoo%3D" alt="Naoki Kosaka"></td>
|
||||||
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12931605/ead494101f364dffa90efe49e36fb494/1?token-time=2145916800&token-hash=NzSFPjIlodXyv41rwK61aZWVZWfI4surJaNj8vWKvqM%3D" alt="Reiju"></td>
|
||||||
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/13034746/c711c7f58e204ecfbc2fd646bc8a4eee/1?token-time=2145916800&token-hash=UERBN4OyP7Nh5XwwdDg0N0IE5cD6_qUQMO81Z5Wizso%3D" alt="Hiratake"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4503830/ccf2cc867ea64de0b524bb2e24b9a1cb/1?token-time=2145916800&token-hash=S1zP0QyLU52Dqq6dtc9qNYyWfW86XrYHiR4NMbeOrnA%3D" alt="dansup"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4950409/28e7d016209243759d9316be2e21381d/2?token-time=2145916800&token-hash=LuEaDkchH3GQWUcTOhBQ8xfKQYF0s5FjlZRd7Yduia8%3D" alt="mikan54951"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/4950409/28e7d016209243759d9316be2e21381d/2?token-time=2145916800&token-hash=LuEaDkchH3GQWUcTOhBQ8xfKQYF0s5FjlZRd7Yduia8%3D" alt="mikan54951"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12531784/93a45137841849329ba692da92ac7c60/1?token-time=2145916800&token-hash=tMosUojzUYJCH_3t--tvYA-SMCyrS__hzSndyaRSnbo%3D" alt="Takashi Shibuya"></td>
|
||||||
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12959468/c249e15aebec4424b5c0f427173671b6/1?token-time=2145916800&token-hash=lubpCEdxAkxPlpR2O6bvZ7BIh8Q4nGf-U_mE1qpjVAQ%3D" alt="fujishan"></td>
|
<td><img src="https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/12959468/c249e15aebec4424b5c0f427173671b6/1?token-time=2145916800&token-hash=lubpCEdxAkxPlpR2O6bvZ7BIh8Q4nGf-U_mE1qpjVAQ%3D" alt="fujishan"></td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
|
<td><a href="https://www.patreon.com/user?u=5881381">Naoki Kosaka</a></td>
|
||||||
|
<td><a href="https://www.patreon.com/user?u=12931605">Reiju</a></td>
|
||||||
|
<td><a href="https://www.patreon.com/hiratake">Hiratake</a></td>
|
||||||
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
|
<td><a href="https://www.patreon.com/dansup">dansup</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=4950409">mikan54951</a></td>
|
<td><a href="https://www.patreon.com/user?u=4950409">mikan54951</a></td>
|
||||||
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
<td><a href="https://www.patreon.com/user?u=12531784">Takashi Shibuya</a></td>
|
||||||
<td><a href="https://www.patreon.com/fujishan">fujishan</a></td>
|
<td><a href="https://www.patreon.com/fujishan">fujishan</a></td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
|
|
||||||
**Last updated:** Sat, 18 Aug 2018 02:02:58 UTC
|
**Last updated:** Wed, 22 Aug 2018 05:25:06 UTC
|
||||||
<!-- PATREON_END -->
|
<!-- PATREON_END -->
|
||||||
|
|
||||||
:four_leaf_clover: Copyright
|
:four_leaf_clover: Copyright
|
||||||
|
144
cli/migration/8.0.0.js
Normal file
144
cli/migration/8.0.0.js
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
const { default: Stats } = require('../../built/models/stats');
|
||||||
|
const { default: User } = require('../../built/models/user');
|
||||||
|
const { default: Note } = require('../../built/models/note');
|
||||||
|
const { default: DriveFile } = require('../../built/models/drive-file');
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const y = now.getFullYear();
|
||||||
|
const m = now.getMonth();
|
||||||
|
const d = now.getDate();
|
||||||
|
const h = now.getHours();
|
||||||
|
const date = new Date(y, m, d, h);
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
await Stats.update({}, {
|
||||||
|
$set: {
|
||||||
|
span: 'day'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
multi: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const localUsersCount = await User.count({
|
||||||
|
host: null
|
||||||
|
});
|
||||||
|
|
||||||
|
const remoteUsersCount = await User.count({
|
||||||
|
host: { $ne: null }
|
||||||
|
});
|
||||||
|
|
||||||
|
const localNotesCount = await Note.count({
|
||||||
|
'_user.host': null
|
||||||
|
});
|
||||||
|
|
||||||
|
const remoteNotesCount = await Note.count({
|
||||||
|
'_user.host': { $ne: null }
|
||||||
|
});
|
||||||
|
|
||||||
|
const localDriveFilesCount = await DriveFile.count({
|
||||||
|
'metadata._user.host': null
|
||||||
|
});
|
||||||
|
|
||||||
|
const remoteDriveFilesCount = await DriveFile.count({
|
||||||
|
'metadata._user.host': { $ne: null }
|
||||||
|
});
|
||||||
|
|
||||||
|
const localDriveFilesSize = await DriveFile
|
||||||
|
.aggregate([{
|
||||||
|
$match: {
|
||||||
|
'metadata._user.host': null,
|
||||||
|
'metadata.deletedAt': { $exists: false }
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
$project: {
|
||||||
|
length: true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
$group: {
|
||||||
|
_id: null,
|
||||||
|
usage: { $sum: '$length' }
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
.then(aggregates => {
|
||||||
|
if (aggregates.length > 0) {
|
||||||
|
return aggregates[0].usage;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const remoteDriveFilesSize = await DriveFile
|
||||||
|
.aggregate([{
|
||||||
|
$match: {
|
||||||
|
'metadata._user.host': { $ne: null },
|
||||||
|
'metadata.deletedAt': { $exists: false }
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
$project: {
|
||||||
|
length: true
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
$group: {
|
||||||
|
_id: null,
|
||||||
|
usage: { $sum: '$length' }
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
.then(aggregates => {
|
||||||
|
if (aggregates.length > 0) {
|
||||||
|
return aggregates[0].usage;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
await Stats.insert({
|
||||||
|
date: date,
|
||||||
|
span: 'hour',
|
||||||
|
users: {
|
||||||
|
local: {
|
||||||
|
total: localUsersCount,
|
||||||
|
diff: 0
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
total: remoteUsersCount,
|
||||||
|
diff: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notes: {
|
||||||
|
local: {
|
||||||
|
total: localNotesCount,
|
||||||
|
diff: 0,
|
||||||
|
diffs: {
|
||||||
|
normal: 0,
|
||||||
|
reply: 0,
|
||||||
|
renote: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
total: remoteNotesCount,
|
||||||
|
diff: 0,
|
||||||
|
diffs: {
|
||||||
|
normal: 0,
|
||||||
|
reply: 0,
|
||||||
|
renote: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
drive: {
|
||||||
|
local: {
|
||||||
|
totalCount: localDriveFilesCount,
|
||||||
|
totalSize: localDriveFilesSize,
|
||||||
|
diffCount: 0,
|
||||||
|
diffSize: 0
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
totalCount: remoteDriveFilesCount,
|
||||||
|
totalSize: remoteDriveFilesSize,
|
||||||
|
diffCount: 0,
|
||||||
|
diffSize: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('done');
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
@ -1,3 +1,3 @@
|
|||||||
files:
|
files:
|
||||||
- source: /locales/ja.yml
|
- source: /locales/ja-JP.yml
|
||||||
translation: /locales/%two_letters_code%.yml
|
translation: /locales/%locale%.yml
|
||||||
|
@ -11,12 +11,12 @@ If you find an untranslated part on Misskey:
|
|||||||
- In fact, `foo` should be a word that is appropriate for the situation and is easy to understand in English.
|
- In fact, `foo` should be a word that is appropriate for the situation and is easy to understand in English.
|
||||||
- For example, if the untranslated portion is the following "タイムライン" you must write: `%i18n:@timeline%`.
|
- For example, if the untranslated portion is the following "タイムライン" you must write: `%i18n:@timeline%`.
|
||||||
|
|
||||||
3. Open the `locales/ja.yml`, check whether the <strong>file name (path)</strong> found in step 1 exists, if not, create it.
|
3. Open the `locales/ja-JP.yml`, check whether the <strong>file name (path)</strong> found in step 1 exists, if not, create it.
|
||||||
- Do not put the beginning of the path `src/client/app/` in the locale file.
|
- Do not put the beginning of the path `src/client/app/` in the locale file.
|
||||||
- For example, in this case we want to modify untranslated parts of `src/client/app/mobile/views/pages/home.vue`, so the key is `mobile/views/pages/home.vue`.
|
- For example, in this case we want to modify untranslated parts of `src/client/app/mobile/views/pages/home.vue`, so the key is `mobile/views/pages/home.vue`.
|
||||||
|
|
||||||
4. Add the text property using the `foo` keyword below the path that you found or created in step 2. Make sure to type your text in quotation marks. Text should always be inside of quotes.
|
4. Add the text property using the `foo` keyword below the path that you found or created in step 2. Make sure to type your text in quotation marks. Text should always be inside of quotes.
|
||||||
- For example, in this case we add timeline: `timeline: "タイムライン"` to `locales/ja.yml`.
|
- For example, in this case we add timeline: `timeline: "タイムライン"` to `locales/ja-JP.yml`.
|
||||||
|
|
||||||
5. And done!
|
5. And done!
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ Si vous trouvez un segment non-traduit sur Misskey :
|
|||||||
- Par exemple, dans ce cas de figure, nous voulons modifier le segment non-traduit de : `src/client/app/mobile/views/pages/home.vue`donc il faut juste écrire : `mobile/views/pages/home.vue` dans les fichiers linguistiques.
|
- Par exemple, dans ce cas de figure, nous voulons modifier le segment non-traduit de : `src/client/app/mobile/views/pages/home.vue`donc il faut juste écrire : `mobile/views/pages/home.vue` dans les fichiers linguistiques.
|
||||||
|
|
||||||
4. Ajoutez la propriété du texte traduit grâce à la clef `foo`, en-dessous du chemin correspondant à votre modification que vous avez trouvé ou créé dans l'étape 2. À côté, veuillez indiquer entre "guillemets" la valeur de votre traduction.
|
4. Ajoutez la propriété du texte traduit grâce à la clef `foo`, en-dessous du chemin correspondant à votre modification que vous avez trouvé ou créé dans l'étape 2. À côté, veuillez indiquer entre "guillemets" la valeur de votre traduction.
|
||||||
- Par exemple, dans ce cas de figure, nous ajoutons la propriété et la traduction `timeline: "Timeline"` à `locales/fr.yml`, mais aussi la propriété et la version originale `timeline: "タイムライン"` à `locales/ja.yml`.
|
- Par exemple, dans ce cas de figure, nous ajoutons la propriété et la traduction `timeline: "Timeline"` à `locales/fr.yml`, mais aussi la propriété et la version originale `timeline: "タイムライン"` à `locales/ja-JP.yml`.
|
||||||
|
|
||||||
5. Vous avez réussi à traduire une portion de misskey !
|
5. Vous avez réussi à traduire une portion de misskey !
|
||||||
|
|
||||||
|
@ -11,12 +11,12 @@ Misskey内の未翻訳箇所を見つけたら
|
|||||||
- `foo`は実際にはその場に適したわかりやすい(英語の)名前にしてください。
|
- `foo`は実際にはその場に適したわかりやすい(英語の)名前にしてください。
|
||||||
- 例えば未翻訳箇所が「タイムライン」というテキストだった場合、`%i18n:@timeline%`のようにします。
|
- 例えば未翻訳箇所が「タイムライン」というテキストだった場合、`%i18n:@timeline%`のようにします。
|
||||||
|
|
||||||
3. `locales/ja.yml`を開き、1.で見つけた<strong>ファイル名(パス)</strong>のキーが存在するか確認し、無ければ作成してください。
|
3. `locales/ja-JP.yml`を開き、1.で見つけた<strong>ファイル名(パス)</strong>のキーが存在するか確認し、無ければ作成してください。
|
||||||
- パスの`src/client/app/`は省略してください。
|
- パスの`src/client/app/`は省略してください。
|
||||||
- 例えば、今回の例では`src/client/app/mobile/views/pages/home.vue`の未翻訳箇所を修正したいので、キーは`mobile/views/pages/home.vue`になります。
|
- 例えば、今回の例では`src/client/app/mobile/views/pages/home.vue`の未翻訳箇所を修正したいので、キーは`mobile/views/pages/home.vue`になります。
|
||||||
|
|
||||||
4. そのキーの直下に2.で置換した`foo`の部分をキーとし、テキストを値とするプロパティを追加します。
|
4. そのキーの直下に2.で置換した`foo`の部分をキーとし、テキストを値とするプロパティを追加します。
|
||||||
- 例えば、今回の例で言うと`locales/ja.yml`に`timeline: "タイムライン"`を追加します。
|
- 例えば、今回の例で言うと`locales/ja-JP.yml`に`timeline: "タイムライン"`を追加します。
|
||||||
|
|
||||||
5. 完了です!
|
5. 完了です!
|
||||||
|
|
||||||
|
13
gulpfile.ts
13
gulpfile.ts
@ -23,7 +23,6 @@ const uglifyes = require('uglify-es');
|
|||||||
|
|
||||||
const locales = require('./locales');
|
const locales = require('./locales');
|
||||||
import { fa } from './src/misc/fa';
|
import { fa } from './src/misc/fa';
|
||||||
import config from './src/config';
|
|
||||||
|
|
||||||
const uglify = uglifyComposer(uglifyes, console);
|
const uglify = uglifyComposer(uglifyes, console);
|
||||||
|
|
||||||
@ -60,7 +59,16 @@ gulp.task('build:copy:views', () =>
|
|||||||
gulp.src('./src/server/web/views/**/*').pipe(gulp.dest('./built/server/web/views'))
|
gulp.src('./src/server/web/views/**/*').pipe(gulp.dest('./built/server/web/views'))
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task('build:copy', ['build:copy:views'], () =>
|
// 互換性のため
|
||||||
|
gulp.task('build:copy:lang', () =>
|
||||||
|
gulp.src(['./built/client/assets/*.*-*.js'])
|
||||||
|
.pipe(rename(path => {
|
||||||
|
path.basename = path.basename.replace(/\-(.*)$/, '');
|
||||||
|
}))
|
||||||
|
.pipe(gulp.dest('./built/client/assets/'))
|
||||||
|
);
|
||||||
|
|
||||||
|
gulp.task('build:copy', ['build:copy:views', 'build:copy:lang'], () =>
|
||||||
gulp.src([
|
gulp.src([
|
||||||
'./build/Release/crypto_key.node',
|
'./build/Release/crypto_key.node',
|
||||||
'./src/const.json',
|
'./src/const.json',
|
||||||
@ -118,7 +126,6 @@ gulp.task('build:client:script', () => {
|
|||||||
const client = require('./built/client/meta.json');
|
const client = require('./built/client/meta.json');
|
||||||
return gulp.src(['./src/client/app/boot.js', './src/client/app/safe.js'])
|
return gulp.src(['./src/client/app/boot.js', './src/client/app/safe.js'])
|
||||||
.pipe(replace('VERSION', JSON.stringify(client.version)))
|
.pipe(replace('VERSION', JSON.stringify(client.version)))
|
||||||
.pipe(replace('API', JSON.stringify(config.api_url)))
|
|
||||||
.pipe(replace('ENV', JSON.stringify(env)))
|
.pipe(replace('ENV', JSON.stringify(env)))
|
||||||
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
|
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
|
||||||
.pipe(isProduction ? uglify({
|
.pipe(isProduction ? uglify({
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# **Please DO NOT edit these files** except `ja.yml`.
|
# **Please DO NOT edit these files** except `ja-JP.yml`.
|
||||||
|
|
||||||
If you want to...
|
If you want to...
|
||||||
* i18n ... please see [Translation guide](../docs/translate.en.md).
|
* i18n ... please see [Translation guide](../docs/translate.en.md).
|
||||||
|
@ -58,7 +58,7 @@ common:
|
|||||||
friday: "金曜日"
|
friday: "金曜日"
|
||||||
saturday: "土曜日"
|
saturday: "土曜日"
|
||||||
reactions:
|
reactions:
|
||||||
like: "Gefällt mir"
|
like: "ええやん"
|
||||||
love: "Lieben"
|
love: "Lieben"
|
||||||
laugh: "Lachen"
|
laugh: "Lachen"
|
||||||
hmm: "Hmm...?"
|
hmm: "Hmm...?"
|
@ -58,7 +58,7 @@ common:
|
|||||||
friday: "Viernes"
|
friday: "Viernes"
|
||||||
saturday: "Sábado"
|
saturday: "Sábado"
|
||||||
reactions:
|
reactions:
|
||||||
like: "me gusta"
|
like: "ええやん"
|
||||||
love: "amor"
|
love: "amor"
|
||||||
laugh: "risa"
|
laugh: "risa"
|
||||||
hmm: "hmm"
|
hmm: "hmm"
|
@ -30,7 +30,7 @@ common:
|
|||||||
quoted-by: "Cité·e par {} :"
|
quoted-by: "Cité·e par {} :"
|
||||||
time:
|
time:
|
||||||
unknown: "inconnu"
|
unknown: "inconnu"
|
||||||
future: "future"
|
future: "à l'instant"
|
||||||
just_now: "à l'instant"
|
just_now: "à l'instant"
|
||||||
seconds_ago: "Il y a {} seconde·s"
|
seconds_ago: "Il y a {} seconde·s"
|
||||||
minutes_ago: "Il y a {} minute·s"
|
minutes_ago: "Il y a {} minute·s"
|
||||||
@ -58,7 +58,7 @@ common:
|
|||||||
friday: "Vendredi"
|
friday: "Vendredi"
|
||||||
saturday: "Samedi"
|
saturday: "Samedi"
|
||||||
reactions:
|
reactions:
|
||||||
like: "Aime"
|
like: "ええやん"
|
||||||
love: "Adore"
|
love: "Adore"
|
||||||
laugh: "Rire"
|
laugh: "Rire"
|
||||||
hmm: "Hmm ... ?"
|
hmm: "Hmm ... ?"
|
||||||
@ -287,7 +287,7 @@ common/views/components/signin.vue:
|
|||||||
signin: "Se connecter"
|
signin: "Se connecter"
|
||||||
or: "Ou"
|
or: "Ou"
|
||||||
signin-with-twitter: "Se connecter via Twitter"
|
signin-with-twitter: "Se connecter via Twitter"
|
||||||
login-failed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
|
login-failed: "Échec d'authentification. Veuillez vérifier que votre nom d'utilisateur et mot de passe sont corrects."
|
||||||
common/views/components/signup.vue:
|
common/views/components/signup.vue:
|
||||||
invitation-code: "Code d’invitation"
|
invitation-code: "Code d’invitation"
|
||||||
invitation-info: "Si vous n’avez pas de code d’invitation, contactez un·e <a href=\"{}\">administrateur·rice</a>."
|
invitation-info: "Si vous n’avez pas de code d’invitation, contactez un·e <a href=\"{}\">administrateur·rice</a>."
|
||||||
@ -443,7 +443,7 @@ desktop/views/components/drive-window.vue:
|
|||||||
desktop/views/components/drive.file.vue:
|
desktop/views/components/drive.file.vue:
|
||||||
avatar: "Avatar"
|
avatar: "Avatar"
|
||||||
banner: "Bannière"
|
banner: "Bannière"
|
||||||
nsfw: "閲覧注意"
|
nsfw: "CW"
|
||||||
contextmenu:
|
contextmenu:
|
||||||
rename: "Renommer"
|
rename: "Renommer"
|
||||||
mark-as-sensitive: "Marquer comme sensible"
|
mark-as-sensitive: "Marquer comme sensible"
|
||||||
@ -638,7 +638,7 @@ desktop/views/components/settings.vue:
|
|||||||
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
show-maps-desc: "位置情報が添付された投稿のマップを自動的に展開します。"
|
||||||
sound: "Son"
|
sound: "Son"
|
||||||
enable-sounds: "Activer le son"
|
enable-sounds: "Activer le son"
|
||||||
enable-sounds-desc: "投稿やメッセージを送受信したときなどにサウンドを再生します。この設定はブラウザに記憶されます。"
|
enable-sounds-desc: "Jouer un son lorsque vous recevez un message. Ce paramètre est sauvegardé dans le navigateur."
|
||||||
volume: "Volume"
|
volume: "Volume"
|
||||||
test: "Test"
|
test: "Test"
|
||||||
mobile: "Mobile"
|
mobile: "Mobile"
|
||||||
@ -699,7 +699,7 @@ desktop/views/components/settings.2fa.vue:
|
|||||||
desktop/views/components/settings.api.vue:
|
desktop/views/components/settings.api.vue:
|
||||||
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
intro: "APIを利用するには、上記のトークンを「i」というキーでパラメータに付加してリクエストします。"
|
||||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
regeneration-of-token: "Si votre jeton est compromis, vous pouvez le régénérer."
|
||||||
regenerate-token: "Regenerer le token"
|
regenerate-token: "Regenerer le token"
|
||||||
token: "Jeton :"
|
token: "Jeton :"
|
||||||
enter-password: "Veuillez entrer le mot de passe"
|
enter-password: "Veuillez entrer le mot de passe"
|
@ -8,16 +8,16 @@ const yaml = require('js-yaml');
|
|||||||
const loadLang = lang => yaml.safeLoad(
|
const loadLang = lang => yaml.safeLoad(
|
||||||
fs.readFileSync(`${__dirname}/${lang}.yml`, 'utf-8'));
|
fs.readFileSync(`${__dirname}/${lang}.yml`, 'utf-8'));
|
||||||
|
|
||||||
const native = loadLang('ja');
|
const native = loadLang('ja-JP');
|
||||||
|
|
||||||
const langs = {
|
const langs = {
|
||||||
'de': loadLang('de'),
|
'de-DE': loadLang('de-DE'),
|
||||||
'en': loadLang('en'),
|
'en-US': loadLang('en-US'),
|
||||||
'fr': loadLang('fr'),
|
'fr-FR': loadLang('fr-FR'),
|
||||||
'ja': native,
|
'ja-JP': native,
|
||||||
'ja-ks': loadLang('ja-ks'),
|
'ja-KS': loadLang('ja-KS'),
|
||||||
'pl': loadLang('pl'),
|
'pl-PL': loadLang('pl-PL'),
|
||||||
'es': loadLang('es')
|
'es-ES': loadLang('es-ES')
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.values(langs).forEach(locale => {
|
Object.values(langs).forEach(locale => {
|
||||||
|
@ -58,7 +58,7 @@ common:
|
|||||||
friday: "金曜日"
|
friday: "金曜日"
|
||||||
saturday: "土曜日"
|
saturday: "土曜日"
|
||||||
reactions:
|
reactions:
|
||||||
like: "いいね"
|
like: "ええやん"
|
||||||
love: "しゅき"
|
love: "しゅき"
|
||||||
laugh: "笑"
|
laugh: "笑"
|
||||||
hmm: "ふぅ~む"
|
hmm: "ふぅ~む"
|
File diff suppressed because it is too large
Load Diff
@ -1,33 +1,33 @@
|
|||||||
---
|
---
|
||||||
meta:
|
meta:
|
||||||
lang: "Português"
|
lang: "日本語 (関西弁)"
|
||||||
divider: ""
|
divider: ""
|
||||||
common:
|
common:
|
||||||
misskey: "A ⭐ of fediverse"
|
misskey: "A ⭐ of fediverse"
|
||||||
about-title: "A ⭐ of fediverse."
|
about-title: "A ⭐ of fediverse."
|
||||||
about: "Misskeyを見つけていただき、ありがとうございます。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>です。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。"
|
about: "ようMisskeyを見つけてくれて、おおきにやで。Misskeyは、地球で生まれた<b>分散マイクロブログSNS</b>やねん。Fediverse(ぎょうさんのSNSで構成されとる宇宙)っちゅうもんの中におるから、お隣さんのSNSとも仲良うさせてもろてんねん。ちょいとやかましい心斎橋から離れて、新しいインターネットにダイブしてみぃひん?"
|
||||||
adblock:
|
adblock:
|
||||||
detected: "広告ブロッカーを無効にしてください"
|
detected: "広告ブロッカーを無効にしてや"
|
||||||
warning: "<strong>Misskeyは広告を掲載していません</strong>が、広告をブロックする機能が有効だと一部の機能が利用できなかったり、不具合が発生する場合があります。"
|
warning: "<strong>Misskeyは広告を掲載してへん</strong>けど、広告をブロックしはる機能がおると一部の機能が利用できんくなったり、不具合が発生するかも分からん。知らんけど。"
|
||||||
application-authorization: "アプリの連携"
|
application-authorization: "アプリの連携"
|
||||||
close: "閉じる"
|
close: "さいなら"
|
||||||
do-not-copy-paste: "ここにコードを入力したり張り付けたりしないでください。アカウントが不正利用される可能性があります。"
|
do-not-copy-paste: "ここにコードを入力したり張り付けたりせんといてください。アカウントが不正利用されるかも分からん。知らんけど。"
|
||||||
got-it: "わかった"
|
got-it: "ほい"
|
||||||
customization-tips:
|
customization-tips:
|
||||||
title: "カスタマイズのヒント"
|
title: "カスタマイズのヒント"
|
||||||
paragraph1: "ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。"
|
paragraph1: "ホームのカスタマイズやと、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりできんねやわ。"
|
||||||
paragraph2: "一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。"
|
paragraph2: "一部のウィジェットは、<strong><strong>右</strong>クリック</strong>したったら表示を変更できんねやわ。"
|
||||||
paragraph3: "ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。"
|
paragraph3: "ウィジェットを削除するんやったら、ヘッダーの<strong>「ゴミ箱」</strong>と書いたぁるエリアにウィジェットをドラッグ&ドロップしてな。"
|
||||||
paragraph4: "カスタマイズを終了するには、右上の「完了」をクリックします。"
|
paragraph4: "カスタマイズを終了するんやったら、右上の「完了」をクリックしてな。"
|
||||||
gotit: "Got it!"
|
gotit: "Got it!"
|
||||||
notification:
|
notification:
|
||||||
file-uploaded: "ファイルがアップロードされました"
|
file-uploaded: "ファイルがアップロードされたで"
|
||||||
message-from: "{}さんからメッセージ:"
|
message-from: "{}はんからメッセージ:"
|
||||||
reversi-invited: "対局への招待があります"
|
reversi-invited: "対局への招待がきとるで"
|
||||||
reversi-invited-by: "{}さんから"
|
reversi-invited-by: "{}はんから"
|
||||||
notified-by: "{}さんから"
|
notified-by: "{}はんから"
|
||||||
reply-from: "{}さんから返信:"
|
reply-from: "{}はんから返信:"
|
||||||
quoted-by: "{}さんが引用:"
|
quoted-by: "{}はんが引用:"
|
||||||
time:
|
time:
|
||||||
unknown: "なぞのじかん"
|
unknown: "なぞのじかん"
|
||||||
future: "未来"
|
future: "未来"
|
||||||
@ -58,41 +58,41 @@ common:
|
|||||||
friday: "金曜日"
|
friday: "金曜日"
|
||||||
saturday: "土曜日"
|
saturday: "土曜日"
|
||||||
reactions:
|
reactions:
|
||||||
like: "いいね"
|
like: "ええやん"
|
||||||
love: "しゅき"
|
love: "好きやねん"
|
||||||
laugh: "笑"
|
laugh: "わろた"
|
||||||
hmm: "ふぅ~む"
|
hmm: "ふぅ~む"
|
||||||
surprise: "わお"
|
surprise: "わお"
|
||||||
congrats: "おめでとう"
|
congrats: "おめでとうさん"
|
||||||
angry: "おこ"
|
angry: "何言うてまんねん"
|
||||||
confused: "こまこまのこまり"
|
confused: "こまこまのこまりやわぁ"
|
||||||
rip: "RIP"
|
rip: "RIP"
|
||||||
pudding: "Pudding"
|
pudding: "アメちゃんちゃうんちゃう?"
|
||||||
note-placeholders:
|
note-placeholders:
|
||||||
a: "今どうしてる?"
|
a: "今なにしてん?"
|
||||||
b: "何かありましたか?"
|
b: "何かあったんか?"
|
||||||
c: "何をお考えですか?"
|
c: "何考えとりますん?"
|
||||||
d: "言いたいことは?"
|
d: "言うときたいことは?"
|
||||||
e: "ここに書いてください"
|
e: "ここに書いてや"
|
||||||
f: "あなたが書くのを待っています..."
|
f: "あんさんが書くんを待っちょります..."
|
||||||
search: "検索"
|
search: "検索"
|
||||||
delete: "削除"
|
delete: "削除"
|
||||||
loading: "読み込み中"
|
loading: "読み込み中"
|
||||||
ok: "わかった"
|
ok: "ほい"
|
||||||
update-available-title: "更新があります"
|
update-available-title: "更新があんで"
|
||||||
update-available: "Misskeyの新しいバージョンがあります({newer}。現在{current}を利用中)。ページを再度読み込みすると更新が適用されます。"
|
update-available: "Misskeyの新しいバージョンがあんで({newer}。現在{current}をつこてるわ)。ページを再度読み込みしたると更新が適用されるわ。"
|
||||||
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
|
my-token-regenerated: "あんさんのトークンが更新されたらしいわ。すまんがとりあえずサインアウトすんで。"
|
||||||
i-like-sushi: "私は(プリンよりむしろ)寿司が好き"
|
i-like-sushi: "寿司(のほうがプリンよりむしろ)ウマい、タコ焼きはあらへんけど。"
|
||||||
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示"
|
show-reversi-board-labels: "リバーシのボードの行と列のラベルを表示や!"
|
||||||
verified-user: "公式アカウント"
|
verified-user: "アメちゃん付きアカウント"
|
||||||
disable-animated-mfm: "投稿内の動きのあるテキストを無効にする"
|
disable-animated-mfm: "投稿内のちょろちょろ動いてんのを止める"
|
||||||
reversi:
|
reversi:
|
||||||
drawn: "引き分け"
|
drawn: "おあいこ"
|
||||||
my-turn: "あなたのターンです"
|
my-turn: "あんさんのターンや"
|
||||||
opponent-turn: "相手のターンです"
|
opponent-turn: "相手のターンや"
|
||||||
turn-of: "{}のターンです"
|
turn-of: "{}のターンや"
|
||||||
past-turn-of: "{}のターン"
|
past-turn-of: "{}のターン"
|
||||||
won: "{}の勝ち"
|
won: "{}の勝ちや!"
|
||||||
black: "黒"
|
black: "黒"
|
||||||
white: "白"
|
white: "白"
|
||||||
total: "合計"
|
total: "合計"
|
||||||
@ -123,67 +123,67 @@ common:
|
|||||||
hashtags: "ハッシュタグ"
|
hashtags: "ハッシュタグ"
|
||||||
deck:
|
deck:
|
||||||
widgets: "ウィジェット"
|
widgets: "ウィジェット"
|
||||||
home: "ホーム"
|
home: "うち"
|
||||||
local: "ローカル"
|
local: "ローカル"
|
||||||
hybrid: "ソーシャル"
|
hybrid: "ソーシャル"
|
||||||
global: "グローバル"
|
global: "グローバル"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
list: "リスト"
|
list: "リスト"
|
||||||
swap-left: "左に移動"
|
swap-left: "左に移動や!"
|
||||||
swap-right: "右に移動"
|
swap-right: "右に移動や!"
|
||||||
swap-up: "上に移動"
|
swap-up: "上に移動!"
|
||||||
swap-down: "下に移動"
|
swap-down: "下に移動!"
|
||||||
remove: "カラムを削除"
|
remove: "カラムを削除や!"
|
||||||
add-column: "カラムを追加"
|
add-column: "カラムを追加!"
|
||||||
rename: "名前を変更"
|
rename: "名前を変更や!"
|
||||||
stack-left: "左に重ねる"
|
stack-left: "左に重ねんで!"
|
||||||
pop-right: "右に出す"
|
pop-right: "右に出すで!"
|
||||||
auth/views/form.vue:
|
auth/views/form.vue:
|
||||||
share-access: "<i>{{ app.name }}</i>があなたのアカウントにアクセスすることを<b>許可</b>しますか?"
|
share-access: "<i>{{ app.name }}</i>があんさんのアカウントにアクセスすんのを<b>許可</b>してもええか?"
|
||||||
permission-ask: "このアプリは次の権限を要求しています:"
|
permission-ask: "このアプリは次の権限を要求してんで:"
|
||||||
account-read: "アカウントの情報を見る。"
|
account-read: "アカウントの情報を見させてもらうで。"
|
||||||
account-write: "アカウントの情報を操作する。"
|
account-write: "アカウントの情報を操作させてもらうで。"
|
||||||
note-write: "投稿する。"
|
note-write: "投稿させてもらうで。"
|
||||||
like-write: "いいねしたりいいね解除する。"
|
like-write: "いいねしたりいいね解除させてもらうで。"
|
||||||
following-write: "フォローしたりフォロー解除する。"
|
following-write: "フォローしたりフォロー解除させてもらうで。"
|
||||||
drive-read: "ドライブを見る。"
|
drive-read: "ドライブを見させてもらうで。"
|
||||||
drive-write: "ドライブを操作する。"
|
drive-write: "ドライブを操作させてもらうで。"
|
||||||
notification-read: "通知を見る。"
|
notification-read: "通知を見させてもらうで。"
|
||||||
notification-write: "通知を操作する。"
|
notification-write: "通知を操作させてもらうで。"
|
||||||
cancel: "キャンセル"
|
cancel: "やめとくわ"
|
||||||
accept: "アクセスを許可"
|
accept: "アクセスを許可や!"
|
||||||
auth/views/index.vue:
|
auth/views/index.vue:
|
||||||
loading: "読み込み中"
|
loading: "読み込み中"
|
||||||
denied: "アプリケーションの連携をキャンセルしました。"
|
denied: "アプリケーションの連携をやめといたわ。"
|
||||||
denied-paragraph: "このアプリがあなたのアカウントにアクセスすることはありません。"
|
denied-paragraph: "このアプリがあんさんのアカウントにアクセスすることは多分あらへん。知らんけど。"
|
||||||
already-authorized: "このアプリは既に連携済みです"
|
already-authorized: "このアプリはもう連携済みやったわ"
|
||||||
allowed: "アプリケーションの連携を許可しました"
|
allowed: "アプリケーションの連携を許可したで"
|
||||||
callback-url: "アプリケーションに戻っています"
|
callback-url: "アプリケーションに戻っとります"
|
||||||
please-go-back: "アプリケーションに戻って、やっていってください。"
|
please-go-back: "アプリケーションに戻って、気張ってってな。"
|
||||||
error: "セッションが存在しません。"
|
error: "セッションが存在してへん。"
|
||||||
sign-in: "サインインしてください"
|
sign-in: "サインインしてや"
|
||||||
common/views/components/games/reversi/reversi.vue:
|
common/views/components/games/reversi/reversi.vue:
|
||||||
matching:
|
matching:
|
||||||
waiting-for: "{}を待っています"
|
waiting-for: "{}を待っとります"
|
||||||
cancel: "キャンセル"
|
cancel: "やめとくわ"
|
||||||
common/views/components/games/reversi/reversi.game.vue:
|
common/views/components/games/reversi/reversi.game.vue:
|
||||||
surrender: "投了"
|
surrender: "投了や..."
|
||||||
surrendered: "投了により"
|
surrendered: "投了により"
|
||||||
is-llotheo: "石の少ない方が勝ち(ロセオ)"
|
is-llotheo: "石の少ない方が勝ち(ロセオ)"
|
||||||
looped-map: "ループマップ"
|
looped-map: "ループマップ"
|
||||||
can-put-everywhere: "どこでも置けるモード"
|
can-put-everywhere: "どこに置いてもええモード"
|
||||||
common/views/components/games/reversi/reversi.index.vue:
|
common/views/components/games/reversi/reversi.index.vue:
|
||||||
title: "Misskey Reversi"
|
title: "Misskey Reversi"
|
||||||
sub-title: "他のMisskeyユーザーとリバーシで対戦しよう"
|
sub-title: "お隣のミスキストはんらとリバーシで対戦や!"
|
||||||
invite: "招待"
|
invite: "招待"
|
||||||
rule: "遊び方"
|
rule: "遊び方"
|
||||||
rule-desc: "リバーシは、相手と交互に石をボードに置いて、相手の石を挟んで自分の色に変えてゆき、最終的に残った石が多い方が勝ちというボードゲームです。"
|
rule-desc: "リバーシは、相手と交互に石をボードに置いて、相手の石を挟んで自分の色に変えてって、最終的に残った石が多い方が勝ちっちゅうボードゲームや。"
|
||||||
mode-invite: "招待"
|
mode-invite: "招待"
|
||||||
mode-invite-desc: "指定したユーザーと対戦するモードです。"
|
mode-invite-desc: "指定したユーザーと対戦するモードや。"
|
||||||
invitations: "対局の招待があります!"
|
invitations: "対局の招待がきてんで!"
|
||||||
my-games: "自分の対局"
|
my-games: "自分の対局"
|
||||||
all-games: "みんなの対局"
|
all-games: "みんなの対局"
|
||||||
enter-username: "ユーザー名を入力してください"
|
enter-username: "ユーザー名を入力してや"
|
||||||
game-state:
|
game-state:
|
||||||
ended: "終了"
|
ended: "終了"
|
||||||
playing: "進行中"
|
playing: "進行中"
|
||||||
@ -202,7 +202,7 @@ common/views/components/games/reversi/reversi.room.vue:
|
|||||||
waiting-for-other: "相手の準備が完了するのを待っています"
|
waiting-for-other: "相手の準備が完了するのを待っています"
|
||||||
waiting-for-me: "あなたの準備が完了するのを待っています"
|
waiting-for-me: "あなたの準備が完了するのを待っています"
|
||||||
waiting-for-both: "準備中"
|
waiting-for-both: "準備中"
|
||||||
cancel: "キャンセル"
|
cancel: "やめとくわ"
|
||||||
ready: "準備完了"
|
ready: "準備完了"
|
||||||
cancel-ready: "準備続行"
|
cancel-ready: "準備続行"
|
||||||
common/views/components/connect-failed.vue:
|
common/views/components/connect-failed.vue:
|
||||||
@ -426,16 +426,16 @@ desktop/views/components/calendar.vue:
|
|||||||
desktop/views/components/choose-file-from-drive-window.vue:
|
desktop/views/components/choose-file-from-drive-window.vue:
|
||||||
choose-file: "ファイル選択中"
|
choose-file: "ファイル選択中"
|
||||||
upload: "PCからドライブにファイルをアップロード"
|
upload: "PCからドライブにファイルをアップロード"
|
||||||
cancel: "キャンセル"
|
cancel: "やめとくわ"
|
||||||
ok: "決定"
|
ok: "決定"
|
||||||
choose-prompt: "ファイルを選択"
|
choose-prompt: "ファイルを選択"
|
||||||
desktop/views/components/choose-folder-from-drive-window.vue:
|
desktop/views/components/choose-folder-from-drive-window.vue:
|
||||||
cancel: "キャンセル"
|
cancel: "やめとくわ"
|
||||||
ok: "決定"
|
ok: "決定"
|
||||||
choose-prompt: "フォルダを選択"
|
choose-prompt: "フォルダを選択"
|
||||||
desktop/views/components/crop-window.vue:
|
desktop/views/components/crop-window.vue:
|
||||||
skip: "クロップをスキップ"
|
skip: "クロップをスキップ"
|
||||||
cancel: "キャンセル"
|
cancel: "やめとくわ"
|
||||||
ok: "決定"
|
ok: "決定"
|
||||||
desktop/views/components/drive-window.vue:
|
desktop/views/components/drive-window.vue:
|
||||||
used: "使用中"
|
used: "使用中"
|
||||||
@ -523,7 +523,7 @@ desktop/views/components/home.vue:
|
|||||||
add-widget: "ウィジェットを追加:"
|
add-widget: "ウィジェットを追加:"
|
||||||
add: "追加"
|
add: "追加"
|
||||||
desktop/views/input-dialog.vue:
|
desktop/views/input-dialog.vue:
|
||||||
cancel: "キャンセル"
|
cancel: "やめとくわ"
|
||||||
ok: "決定"
|
ok: "決定"
|
||||||
desktop/views/components/messaging-room-window.vue:
|
desktop/views/components/messaging-room-window.vue:
|
||||||
title: "メッセージ:"
|
title: "メッセージ:"
|
||||||
@ -592,7 +592,7 @@ desktop/views/components/progress-dialog.vue:
|
|||||||
waiting: "待機中"
|
waiting: "待機中"
|
||||||
desktop/views/components/renote-form.vue:
|
desktop/views/components/renote-form.vue:
|
||||||
quote: "引用する..."
|
quote: "引用する..."
|
||||||
cancel: "キャンセル"
|
cancel: "やめとくわ"
|
||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
reposting: "しています..."
|
reposting: "しています..."
|
||||||
success: "Renoteしました!"
|
success: "Renoteしました!"
|
||||||
@ -859,7 +859,7 @@ desktop/views/pages/note.vue:
|
|||||||
desktop/views/pages/selectdrive.vue:
|
desktop/views/pages/selectdrive.vue:
|
||||||
title: "ファイルを選択してください"
|
title: "ファイルを選択してください"
|
||||||
ok: "決定"
|
ok: "決定"
|
||||||
cancel: "キャンセル"
|
cancel: "やめとくわ"
|
||||||
upload: "PCからドライブにファイルをアップロード"
|
upload: "PCからドライブにファイルをアップロード"
|
||||||
desktop/views/pages/search.vue:
|
desktop/views/pages/search.vue:
|
||||||
not-available: "検索機能はインスタンスの設定で無効になっています。"
|
not-available: "検索機能はインスタンスの設定で無効になっています。"
|
1412
locales/ja-ks.yml
1412
locales/ja-ks.yml
File diff suppressed because it is too large
Load Diff
@ -58,7 +58,7 @@ common:
|
|||||||
friday: "금요일"
|
friday: "금요일"
|
||||||
saturday: "토요일"
|
saturday: "토요일"
|
||||||
reactions:
|
reactions:
|
||||||
like: "좋네"
|
like: "ええやん"
|
||||||
love: "좋아"
|
love: "좋아"
|
||||||
laugh: "크크"
|
laugh: "크크"
|
||||||
hmm: "음..."
|
hmm: "음..."
|
@ -58,7 +58,7 @@ common:
|
|||||||
friday: "Piątek"
|
friday: "Piątek"
|
||||||
saturday: "Sobota"
|
saturday: "Sobota"
|
||||||
reactions:
|
reactions:
|
||||||
like: "Lubię"
|
like: "ええやん"
|
||||||
love: "Kocham"
|
love: "Kocham"
|
||||||
laugh: "Śmieszne"
|
laugh: "Śmieszne"
|
||||||
hmm: "Hmm…?"
|
hmm: "Hmm…?"
|
1219
locales/pt-PT.yml
Normal file
1219
locales/pt-PT.yml
Normal file
File diff suppressed because it is too large
Load Diff
@ -58,7 +58,7 @@ common:
|
|||||||
friday: "金曜日"
|
friday: "金曜日"
|
||||||
saturday: "土曜日"
|
saturday: "土曜日"
|
||||||
reactions:
|
reactions:
|
||||||
like: "いいね"
|
like: "ええやん"
|
||||||
love: "しゅき"
|
love: "しゅき"
|
||||||
laugh: "笑"
|
laugh: "笑"
|
||||||
hmm: "ふぅ~む"
|
hmm: "ふぅ~む"
|
@ -58,7 +58,7 @@ common:
|
|||||||
friday: "金曜日"
|
friday: "金曜日"
|
||||||
saturday: "土曜日"
|
saturday: "土曜日"
|
||||||
reactions:
|
reactions:
|
||||||
like: "いいね"
|
like: "ええやん"
|
||||||
love: "しゅき"
|
love: "しゅき"
|
||||||
laugh: "笑"
|
laugh: "笑"
|
||||||
hmm: "ふぅ~む"
|
hmm: "ふぅ~む"
|
15
package.json
15
package.json
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "7.1.2",
|
"version": "8.0.0",
|
||||||
"clientVersion": "1.0.8693",
|
"clientVersion": "1.0.8790",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
@ -157,6 +157,7 @@
|
|||||||
"monk": "6.0.6",
|
"monk": "6.0.6",
|
||||||
"ms": "2.1.1",
|
"ms": "2.1.1",
|
||||||
"nan": "2.10.0",
|
"nan": "2.10.0",
|
||||||
|
"nested-property": "0.0.7",
|
||||||
"node-sass": "4.9.3",
|
"node-sass": "4.9.3",
|
||||||
"node-sass-json-importer": "3.3.1",
|
"node-sass-json-importer": "3.3.1",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
@ -181,7 +182,7 @@
|
|||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"sass-loader": "7.1.0",
|
"sass-loader": "7.1.0",
|
||||||
"seedrandom": "2.4.4",
|
"seedrandom": "2.4.4",
|
||||||
"sharp": "0.20.5",
|
"sharp": "0.20.7",
|
||||||
"showdown": "1.8.6",
|
"showdown": "1.8.6",
|
||||||
"showdown-highlightjs-extension": "0.1.2",
|
"showdown-highlightjs-extension": "0.1.2",
|
||||||
"single-line-log": "1.1.2",
|
"single-line-log": "1.1.2",
|
||||||
@ -190,7 +191,7 @@
|
|||||||
"style-loader": "0.22.1",
|
"style-loader": "0.22.1",
|
||||||
"stylus": "0.54.5",
|
"stylus": "0.54.5",
|
||||||
"stylus-loader": "3.0.2",
|
"stylus-loader": "3.0.2",
|
||||||
"summaly": "2.1.3",
|
"summaly": "2.1.4",
|
||||||
"systeminformation": "3.42.9",
|
"systeminformation": "3.42.9",
|
||||||
"syuilo-password-strength": "0.0.1",
|
"syuilo-password-strength": "0.0.1",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
@ -206,9 +207,9 @@
|
|||||||
"v-animate-css": "0.0.2",
|
"v-animate-css": "0.0.2",
|
||||||
"vue": "2.5.17",
|
"vue": "2.5.17",
|
||||||
"vue-cropperjs": "2.2.1",
|
"vue-cropperjs": "2.2.1",
|
||||||
"vue-js-modal": "1.3.17",
|
"vue-js-modal": "1.3.18",
|
||||||
"vue-json-tree-view": "2.1.4",
|
"vue-json-tree-view": "2.1.4",
|
||||||
"vue-loader": "15.3.0",
|
"vue-loader": "15.4.0",
|
||||||
"vue-router": "3.0.1",
|
"vue-router": "3.0.1",
|
||||||
"vue-style-loader": "4.1.2",
|
"vue-style-loader": "4.1.2",
|
||||||
"vue-template-compiler": "2.5.17",
|
"vue-template-compiler": "2.5.17",
|
||||||
@ -217,7 +218,7 @@
|
|||||||
"vuex-persistedstate": "2.5.4",
|
"vuex-persistedstate": "2.5.4",
|
||||||
"web-push": "3.3.2",
|
"web-push": "3.3.2",
|
||||||
"webfinger.js": "2.6.6",
|
"webfinger.js": "2.6.6",
|
||||||
"webpack": "4.16.5",
|
"webpack": "4.17.1",
|
||||||
"webpack-cli": "3.1.0",
|
"webpack-cli": "3.1.0",
|
||||||
"websocket": "1.0.26",
|
"websocket": "1.0.26",
|
||||||
"ws": "6.0.0",
|
"ws": "6.0.0",
|
||||||
|
@ -32,16 +32,24 @@
|
|||||||
//#region Detect app name
|
//#region Detect app name
|
||||||
let app = null;
|
let app = null;
|
||||||
|
|
||||||
if (url.pathname == '/docs' || url.pathname.startsWith('/docs/')) app = 'docs';
|
if (`${url.pathname}/`.startsWith('/docs/')) app = 'docs';
|
||||||
if (url.pathname == '/dev' || url.pathname.startsWith('/dev/')) app = 'dev';
|
if (`${url.pathname}/`.startsWith('/dev/')) app = 'dev';
|
||||||
if (url.pathname == '/auth' || url.pathname.startsWith('/auth/')) app = 'auth';
|
if (`${url.pathname}/`.startsWith('/auth/')) app = 'auth';
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Detect the user language
|
//#region Detect the user language
|
||||||
let lang = navigator.language.split('-')[0];
|
let lang = null;
|
||||||
|
|
||||||
// The default language is English
|
if (LANGS.includes(navigator.language)) {
|
||||||
if (!LANGS.includes(lang)) lang = 'en';
|
lang = navigator.language;
|
||||||
|
} else {
|
||||||
|
lang = LANGS.find(x => x.split('-')[0] == navigator.language);
|
||||||
|
|
||||||
|
if (lang == null) {
|
||||||
|
// Fallback
|
||||||
|
lang = 'en-US';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (settings) {
|
if (settings) {
|
||||||
if (settings.device.lang) lang = settings.device.lang;
|
if (settings.device.lang) lang = settings.device.lang;
|
||||||
@ -104,7 +112,7 @@
|
|||||||
// グローバルにタイマーIDを代入しておく
|
// グローバルにタイマーIDを代入しておく
|
||||||
window.mkBootTimer = window.setTimeout(async () => {
|
window.mkBootTimer = window.setTimeout(async () => {
|
||||||
// Fetch meta
|
// Fetch meta
|
||||||
const res = await fetch(API + '/meta', {
|
const res = await fetch('/api/meta', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
cache: 'no-cache'
|
cache: 'no-cache'
|
||||||
});
|
});
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="board">
|
<div class="board">
|
||||||
<div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels">
|
<div class="labels-x" v-if="this.$store.state.settings.games.reversi.showBoardLabels">
|
||||||
<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
|
<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels">
|
<div class="labels-y" v-if="this.$store.state.settings.games.reversi.showBoardLabels">
|
||||||
<div v-for="i in game.settings.map.length">{{ i }}</div>
|
<div v-for="i in game.settings.map.length">{{ i }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cells" :style="cellsStyle">
|
<div class="cells" :style="cellsStyle">
|
||||||
@ -30,15 +30,15 @@
|
|||||||
:class="{ empty: stone == null, none: o.map[i] == 'null', isEnded: game.isEnded, myTurn: !game.isEnded && isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id, i) : null, prev: o.prevPos == i }"
|
:class="{ empty: stone == null, none: o.map[i] == 'null', isEnded: game.isEnded, myTurn: !game.isEnded && isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id, i) : null, prev: o.prevPos == i }"
|
||||||
@click="set(i)"
|
@click="set(i)"
|
||||||
:title="`${String.fromCharCode(65 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`">
|
:title="`${String.fromCharCode(65 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`">
|
||||||
<img v-if="stone === true" :src="blackUser.avatarUrl" alt="">
|
<img v-if="stone === true" :src="blackUser.avatarUrl" alt="black" :class="{ contrast: $store.state.settings.games.reversi.useContrastStones }">
|
||||||
<img v-if="stone === false" :src="whiteUser.avatarUrl" alt="">
|
<img v-if="stone === false" :src="whiteUser.avatarUrl" alt="white" :class="{ contrast: $store.state.settings.games.reversi.useContrastStones }">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels">
|
<div class="labels-y" v-if="this.$store.state.settings.games.reversi.showBoardLabels">
|
||||||
<div v-for="i in game.settings.map.length">{{ i }}</div>
|
<div v-for="i in game.settings.map.length">{{ i }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels">
|
<div class="labels-x" v-if="this.$store.state.settings.games.reversi.showBoardLabels">
|
||||||
<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
|
<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -421,6 +421,13 @@ root(isDark)
|
|||||||
width 100%
|
width 100%
|
||||||
height 100%
|
height 100%
|
||||||
|
|
||||||
|
&.contrast
|
||||||
|
&[alt="black"]
|
||||||
|
filter brightness(.5)
|
||||||
|
|
||||||
|
&[alt="white"]
|
||||||
|
filter brightness(2)
|
||||||
|
|
||||||
> .graph
|
> .graph
|
||||||
display grid
|
display grid
|
||||||
grid-template-columns repeat(61, 1fr)
|
grid-template-columns repeat(61, 1fr)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<i>・</i>
|
<i>・</i>
|
||||||
<a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a>
|
<a :href="feedbackUrl" target="_blank">%i18n:@feedback%</a>
|
||||||
<i>・</i>
|
<i>・</i>
|
||||||
<a :href="devUrl">%i18n:@develop%</a>
|
<a href="/dev">%i18n:@develop%</a>
|
||||||
<i>・</i>
|
<i>・</i>
|
||||||
<a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on %fa:B twitter%</a>
|
<a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on %fa:B twitter%</a>
|
||||||
</span>
|
</span>
|
||||||
@ -14,18 +14,21 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { docsUrl, statsUrl, statusUrl, devUrl, repositoryUrl, feedbackUrl, lang } from '../../../config';
|
import { lang } from '../../../config';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
aboutUrl: `${docsUrl}/${lang}/about`,
|
aboutUrl: `/docs/${lang}/about`,
|
||||||
statsUrl,
|
repositoryUrl: 'https://github.com/syuilo/misskey',
|
||||||
statusUrl,
|
feedbackUrl: 'https://github.com/syuilo/misskey/issues/new'
|
||||||
devUrl,
|
|
||||||
repositoryUrl: repositoryUrl || `https://github.com/syuilo/misskey`,
|
|
||||||
feedbackUrl: feedbackUrl || `https://github.com/syuilo/misskey/issues/new`
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
(this as any).os.getMeta().then(meta => {
|
||||||
|
if (meta.repositoryUrl) this.repositoryUrl = meta.repositoryUrl;
|
||||||
|
if (meta.feedbackUrl) this.feedbackUrl = meta.feedbackUrl;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -53,9 +53,8 @@ export default Vue.extend({
|
|||||||
this.signing = true;
|
this.signing = true;
|
||||||
|
|
||||||
(this as any).api('signin', {
|
(this as any).api('signin', {
|
||||||
// password という名前(または username とのペア?)では何らかのフィルタリングがされるっぽい?
|
username: this.username,
|
||||||
x: this.username,
|
password: this.password,
|
||||||
y: this.password,
|
|
||||||
token: this.user && this.user.twoFactorEnabled ? this.token : undefined
|
token: this.user && this.user.twoFactorEnabled ? this.token : undefined
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
location.reload();
|
location.reload();
|
||||||
|
@ -1,41 +1,43 @@
|
|||||||
<template>
|
<template>
|
||||||
<form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()">
|
<form class="mk-signup" @submit.prevent="onSubmit" :autocomplete="Math.random()">
|
||||||
<ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required>
|
<template v-if="meta">
|
||||||
<span>%i18n:@invitation-code%</span>
|
<ui-input v-if="meta.disableRegistration" v-model="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required>
|
||||||
<span slot="prefix">%fa:id-card-alt%</span>
|
<span>%i18n:@invitation-code%</span>
|
||||||
<p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p>
|
<span slot="prefix">%fa:id-card-alt%</span>
|
||||||
</ui-input>
|
<p slot="text" v-html="'%i18n:@invitation-info%'.replace('{}', meta.maintainer.url)"></p>
|
||||||
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername">
|
</ui-input>
|
||||||
<span>%i18n:@username%</span>
|
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @input="onChangeUsername">
|
||||||
<span slot="prefix">@</span>
|
<span>%i18n:@username%</span>
|
||||||
<span slot="suffix">@{{ host }}</span>
|
<span slot="prefix">@</span>
|
||||||
<p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw% %i18n:@checking%</p>
|
<span slot="suffix">@{{ host }}</span>
|
||||||
<p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw% %i18n:@available%</p>
|
<p slot="text" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw% %i18n:@checking%</p>
|
||||||
<p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@unavailable%</p>
|
<p slot="text" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw% %i18n:@available%</p>
|
||||||
<p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@error%</p>
|
<p slot="text" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@unavailable%</p>
|
||||||
<p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@invalid-format%</p>
|
<p slot="text" v-if="usernameState == 'error'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@error%</p>
|
||||||
<p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p>
|
<p slot="text" v-if="usernameState == 'invalid-format'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@invalid-format%</p>
|
||||||
<p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p>
|
<p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p>
|
||||||
</ui-input>
|
<p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p>
|
||||||
<ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true">
|
</ui-input>
|
||||||
<span>%i18n:@password%</span>
|
<ui-input v-model="password" type="password" :autocomplete="Math.random()" required @input="onChangePassword" :with-password-meter="true">
|
||||||
<span slot="prefix">%fa:lock%</span>
|
<span>%i18n:@password%</span>
|
||||||
<div slot="text">
|
<span slot="prefix">%fa:lock%</span>
|
||||||
<p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p>
|
<div slot="text">
|
||||||
<p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p>
|
<p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p>
|
||||||
<p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p>
|
<p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p>
|
||||||
</div>
|
<p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p>
|
||||||
</ui-input>
|
</div>
|
||||||
<ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype">
|
</ui-input>
|
||||||
<span>%i18n:@password% (%i18n:@retype%)</span>
|
<ui-input v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @input="onChangePasswordRetype">
|
||||||
<span slot="prefix">%fa:lock%</span>
|
<span>%i18n:@password% (%i18n:@retype%)</span>
|
||||||
<div slot="text">
|
<span slot="prefix">%fa:lock%</span>
|
||||||
<p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p>
|
<div slot="text">
|
||||||
<p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p>
|
<p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p>
|
||||||
</div>
|
<p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p>
|
||||||
</ui-input>
|
</div>
|
||||||
<div v-if="meta && meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div>
|
</ui-input>
|
||||||
<ui-button type="submit">%i18n:@create%</ui-button>
|
<div v-if="meta.recaptchaSitekey != null" class="g-recaptcha" :data-sitekey="meta.recaptchaSitekey" style="margin: 16px 0;"></div>
|
||||||
|
<ui-button type="submit">%i18n:@create%</ui-button>
|
||||||
|
</template>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<iframe v-if="player" :src="player" heigth="250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen />
|
<div v-if="player.url" class="player" :style="`padding: ${(player.height || 0) / (player.width || 1) * 100}% 0 0`">
|
||||||
|
<iframe :src="player.url" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen />
|
||||||
|
</div>
|
||||||
<div v-else-if="tweetUrl && detail" class="twitter">
|
<div v-else-if="tweetUrl && detail" class="twitter">
|
||||||
<blockquote ref="tweet" class="twitter-tweet" :data-theme="$store.state.device.darkmode ? 'dark' : null">
|
<blockquote ref="tweet" class="twitter-tweet" :data-theme="$store.state.device.darkmode ? 'dark' : null">
|
||||||
<a :href="url"></a>
|
<a :href="url"></a>
|
||||||
@ -46,7 +48,11 @@ export default Vue.extend({
|
|||||||
thumbnail: null,
|
thumbnail: null,
|
||||||
icon: null,
|
icon: null,
|
||||||
sitename: null,
|
sitename: null,
|
||||||
player: null,
|
player: {
|
||||||
|
url: null,
|
||||||
|
width: null,
|
||||||
|
height: null
|
||||||
|
},
|
||||||
tweetUrl: null,
|
tweetUrl: null,
|
||||||
misskeyUrl
|
misskeyUrl
|
||||||
};
|
};
|
||||||
@ -170,9 +176,17 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
iframe
|
.twitter
|
||||||
|
position relative
|
||||||
width 100%
|
width 100%
|
||||||
|
|
||||||
|
> iframe
|
||||||
|
height 100%
|
||||||
|
left 0
|
||||||
|
position absolute
|
||||||
|
top 0
|
||||||
|
width 100%
|
||||||
|
|
||||||
root(isDark)
|
root(isDark)
|
||||||
> a
|
> a
|
||||||
display block
|
display block
|
||||||
|
@ -4,7 +4,6 @@ declare const _THEME_COLOR_: string;
|
|||||||
declare const _COPYRIGHT_: string;
|
declare const _COPYRIGHT_: string;
|
||||||
declare const _VERSION_: string;
|
declare const _VERSION_: string;
|
||||||
declare const _CODENAME_: string;
|
declare const _CODENAME_: string;
|
||||||
declare const _LICENSE_: string;
|
|
||||||
|
|
||||||
const address = new URL(location.href);
|
const address = new URL(location.href);
|
||||||
|
|
||||||
@ -19,4 +18,3 @@ export const themeColor = _THEME_COLOR_;
|
|||||||
export const copyright = _COPYRIGHT_;
|
export const copyright = _COPYRIGHT_;
|
||||||
export const version = _VERSION_;
|
export const version = _VERSION_;
|
||||||
export const codename = _CODENAME_;
|
export const codename = _CODENAME_;
|
||||||
export const license = _LICENSE_;
|
|
||||||
|
@ -56,8 +56,9 @@
|
|||||||
<mk-switch v-model="$store.state.settings.showMaps" @change="onChangeShowMaps" text="%i18n:@show-maps%">
|
<mk-switch v-model="$store.state.settings.showMaps" @change="onChangeShowMaps" text="%i18n:@show-maps%">
|
||||||
<span>%i18n:@show-maps-desc%</span>
|
<span>%i18n:@show-maps-desc%</span>
|
||||||
</mk-switch>
|
</mk-switch>
|
||||||
<mk-switch v-model="$store.state.settings.reversiBoardLabels" @change="onChangeReversiBoardLabels" text="%i18n:common.show-reversi-board-labels%"/>
|
|
||||||
<mk-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm" text="%i18n:common.disable-animated-mfm%"/>
|
<mk-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm" text="%i18n:common.disable-animated-mfm%"/>
|
||||||
|
<mk-switch v-model="$store.state.settings.games.reversi.showBoardLabels" @change="onChangeReversiBoardLabels" text="%i18n:common.show-reversi-board-labels%"/>
|
||||||
|
<mk-switch v-model="$store.state.settings.games.reversi.useContrastStones" @change="onChangeUseContrastReversiStones" text="%i18n:common.use-contrast-reversi-stones%"/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="web" v-show="page == 'web'">
|
<section class="web" v-show="page == 'web'">
|
||||||
@ -191,12 +192,6 @@
|
|||||||
<button class="ui button block" @click="taskmngr">%i18n:@task-manager%</button>
|
<button class="ui button block" @click="taskmngr">%i18n:@task-manager%</button>
|
||||||
</details>
|
</details>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="other" v-show="page == 'other'">
|
|
||||||
<h1>%i18n:@license%</h1>
|
|
||||||
<div v-html="license"></div>
|
|
||||||
<a :href="licenseUrl" target="_blank">%i18n:@third-parties%</a>
|
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -211,7 +206,7 @@ import XApi from './settings.api.vue';
|
|||||||
import XApps from './settings.apps.vue';
|
import XApps from './settings.apps.vue';
|
||||||
import XSignins from './settings.signins.vue';
|
import XSignins from './settings.signins.vue';
|
||||||
import XDrive from './settings.drive.vue';
|
import XDrive from './settings.drive.vue';
|
||||||
import { url, docsUrl, license, lang, langs, version } from '../../../config';
|
import { url, langs, version } from '../../../config';
|
||||||
import checkForUpdate from '../../../common/scripts/check-for-update';
|
import checkForUpdate from '../../../common/scripts/check-for-update';
|
||||||
import MkTaskManager from './taskmanager.vue';
|
import MkTaskManager from './taskmanager.vue';
|
||||||
|
|
||||||
@ -230,7 +225,6 @@ export default Vue.extend({
|
|||||||
return {
|
return {
|
||||||
page: 'profile',
|
page: 'profile',
|
||||||
meta: null,
|
meta: null,
|
||||||
license,
|
|
||||||
version,
|
version,
|
||||||
langs,
|
langs,
|
||||||
latestVersion: undefined,
|
latestVersion: undefined,
|
||||||
@ -238,10 +232,6 @@ export default Vue.extend({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
licenseUrl(): string {
|
|
||||||
return `${docsUrl}/${lang}/license`;
|
|
||||||
},
|
|
||||||
|
|
||||||
apiViaStream: {
|
apiViaStream: {
|
||||||
get() { return this.$store.state.device.apiViaStream; },
|
get() { return this.$store.state.device.apiViaStream; },
|
||||||
set(value) { this.$store.commit('device/set', { key: 'apiViaStream', value }); }
|
set(value) { this.$store.commit('device/set', { key: 'apiViaStream', value }); }
|
||||||
@ -387,7 +377,13 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
onChangeReversiBoardLabels(v) {
|
onChangeReversiBoardLabels(v) {
|
||||||
this.$store.dispatch('settings/set', {
|
this.$store.dispatch('settings/set', {
|
||||||
key: 'reversiBoardLabels',
|
key: 'games.reversi.showBoardLabels',
|
||||||
|
value: v
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onChangeUseContrastReversiStones(v) {
|
||||||
|
this.$store.dispatch('settings/set', {
|
||||||
|
key: 'games.reversi.useContrastStones',
|
||||||
value: v
|
value: v
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -30,10 +30,8 @@
|
|||||||
<li @click="settings">
|
<li @click="settings">
|
||||||
<p>%fa:cog%<span>%i18n:@settings%</span>%fa:angle-right%</p>
|
<p>%fa:cog%<span>%i18n:@settings%</span>%fa:angle-right%</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
<li v-if="$store.state.i.isAdmin">
|
||||||
<ul>
|
<router-link to="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</router-link>
|
||||||
<li @click="signout">
|
|
||||||
<p class="signout">%fa:power-off%<span>%i18n:@signout%</span></p>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
@ -41,6 +39,11 @@
|
|||||||
<p><span>%i18n:@dark%</span><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template></p>
|
<p><span>%i18n:@dark%</span><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template></p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li @click="signout">
|
||||||
|
<p class="signout">%fa:power-off%<span>%i18n:@signout%</span></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
<x-cpu-memory :connection="connection"/>
|
<x-cpu-memory :connection="connection"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" v-model="disableRegistration" @change="updateMeta">
|
||||||
|
<span>disableRegistration</span>
|
||||||
|
</label>
|
||||||
<button class="ui" @click="invite">%i18n:@invite%</button>
|
<button class="ui" @click="invite">%i18n:@invite%</button>
|
||||||
<p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p>
|
<p v-if="inviteCode">Code: <code>{{ inviteCode }}</code></p>
|
||||||
</div>
|
</div>
|
||||||
@ -28,6 +32,7 @@ export default Vue.extend({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
stats: null,
|
stats: null,
|
||||||
|
disableRegistration: false,
|
||||||
inviteCode: null,
|
inviteCode: null,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null
|
connectionId: null
|
||||||
@ -37,6 +42,10 @@ export default Vue.extend({
|
|||||||
this.connection = (this as any).os.streams.serverStatsStream.getConnection();
|
this.connection = (this as any).os.streams.serverStatsStream.getConnection();
|
||||||
this.connectionId = (this as any).os.streams.serverStatsStream.use();
|
this.connectionId = (this as any).os.streams.serverStatsStream.use();
|
||||||
|
|
||||||
|
(this as any).os.getMeta().then(meta => {
|
||||||
|
this.disableRegistration = meta.disableRegistration;
|
||||||
|
});
|
||||||
|
|
||||||
(this as any).api('stats').then(stats => {
|
(this as any).api('stats').then(stats => {
|
||||||
this.stats = stats;
|
this.stats = stats;
|
||||||
});
|
});
|
||||||
@ -49,6 +58,11 @@ export default Vue.extend({
|
|||||||
(this as any).api('admin/invite').then(x => {
|
(this as any).api('admin/invite').then(x => {
|
||||||
this.inviteCode = x.code;
|
this.inviteCode = x.code;
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
updateMeta() {
|
||||||
|
(this as any).api('admin/update-meta', {
|
||||||
|
disableRegistration: this.disableRegistration
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -99,7 +99,7 @@ export default Vue.extend({
|
|||||||
cursor pointer
|
cursor pointer
|
||||||
padding 0 16px
|
padding 0 16px
|
||||||
margin 0
|
margin 0
|
||||||
min-width 150px
|
min-width 100px
|
||||||
line-height 36px
|
line-height 36px
|
||||||
font-size 14px
|
font-size 14px
|
||||||
font-weight bold
|
font-weight bold
|
||||||
|
@ -12,6 +12,7 @@ import noteCard from './note-card.vue';
|
|||||||
import userCard from './user-card.vue';
|
import userCard from './user-card.vue';
|
||||||
import noteDetail from './note-detail.vue';
|
import noteDetail from './note-detail.vue';
|
||||||
import followButton from './follow-button.vue';
|
import followButton from './follow-button.vue';
|
||||||
|
import muteButton from './mute-button.vue';
|
||||||
import friendsMaker from './friends-maker.vue';
|
import friendsMaker from './friends-maker.vue';
|
||||||
import notification from './notification.vue';
|
import notification from './notification.vue';
|
||||||
import notifications from './notifications.vue';
|
import notifications from './notifications.vue';
|
||||||
@ -36,6 +37,7 @@ Vue.component('mk-note-card', noteCard);
|
|||||||
Vue.component('mk-user-card', userCard);
|
Vue.component('mk-user-card', userCard);
|
||||||
Vue.component('mk-note-detail', noteDetail);
|
Vue.component('mk-note-detail', noteDetail);
|
||||||
Vue.component('mk-follow-button', followButton);
|
Vue.component('mk-follow-button', followButton);
|
||||||
|
Vue.component('mk-mute-button', muteButton);
|
||||||
Vue.component('mk-friends-maker', friendsMaker);
|
Vue.component('mk-friends-maker', friendsMaker);
|
||||||
Vue.component('mk-notification', notification);
|
Vue.component('mk-notification', notification);
|
||||||
Vue.component('mk-notifications', notifications);
|
Vue.component('mk-notifications', notifications);
|
||||||
|
79
src/client/app/mobile/views/components/mute-button.vue
Normal file
79
src/client/app/mobile/views/components/mute-button.vue
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
class="mk-mute-button"
|
||||||
|
:class="{ active: user.isMuted }"
|
||||||
|
@click="onClick">
|
||||||
|
<span v-if="!user.isMuted">%fa:eye-slash% %i18n:@mute%</span>
|
||||||
|
<span v-else>%fa:eye% %i18n:@unmute%</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default Vue.extend({
|
||||||
|
props: {
|
||||||
|
user: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onClick() {
|
||||||
|
if (!this.user.isMuted) {
|
||||||
|
this.mute();
|
||||||
|
} else {
|
||||||
|
this.unmute();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mute() {
|
||||||
|
(this as any).api('mute/create', { userId: this.user.id})
|
||||||
|
.then(() => { this.user.isMuted = true })
|
||||||
|
.catch(() => { alert('error')})
|
||||||
|
},
|
||||||
|
unmute() {
|
||||||
|
(this as any).api('mute/delete', { userId: this.user.id })
|
||||||
|
.then(() => { this.user.isMuted = false })
|
||||||
|
.catch(() => { alert('error') })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
@import '~const.styl'
|
||||||
|
|
||||||
|
.mk-mute-button
|
||||||
|
display block
|
||||||
|
user-select none
|
||||||
|
cursor pointer
|
||||||
|
padding 0 16px
|
||||||
|
margin 0
|
||||||
|
min-width 100px
|
||||||
|
line-height 36px
|
||||||
|
font-size 14px
|
||||||
|
font-weight bold
|
||||||
|
color $theme-color
|
||||||
|
background transparent
|
||||||
|
outline none
|
||||||
|
border solid 1px $theme-color
|
||||||
|
border-radius 36px
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background rgba($theme-color, 0.1)
|
||||||
|
|
||||||
|
&:active
|
||||||
|
background rgba($theme-color, 0.2)
|
||||||
|
|
||||||
|
&.active
|
||||||
|
color $theme-color-foreground
|
||||||
|
background $theme-color
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background lighten($theme-color, 10%)
|
||||||
|
border-color lighten($theme-color, 10%)
|
||||||
|
&:active
|
||||||
|
background darken($theme-color, 10%)
|
||||||
|
border-color darken($theme-color, 10%)
|
||||||
|
|
||||||
|
</style>
|
@ -30,6 +30,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li>
|
<li><a @click="search">%fa:search%%i18n:@search%%fa:angle-right%</a></li>
|
||||||
<li><router-link to="/i/settings" :data-active="$route.name == 'settings'">%fa:cog%%i18n:@settings%%fa:angle-right%</router-link></li>
|
<li><router-link to="/i/settings" :data-active="$route.name == 'settings'">%fa:cog%%i18n:@settings%%fa:angle-right%</router-link></li>
|
||||||
|
<li v-if="$store.getters.isSignedIn && $store.state.i.isAdmin"><router-link to="/admin">%fa:terminal%<span>%i18n:@admin%</span>%fa:angle-right%</router-link></li>
|
||||||
<li @click="dark"><p><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template><span>%i18n:@darkmode%</span></p></li>
|
<li @click="dark"><p><template v-if="$store.state.device.darkmode">%fa:moon%</template><template v-else>%fa:R moon%</template><span>%i18n:@darkmode%</span></p></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -41,7 +42,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { docsUrl, lang } from '../../../config';
|
import { lang } from '../../../config';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
props: ['isOpen'],
|
props: ['isOpen'],
|
||||||
@ -50,7 +51,7 @@ export default Vue.extend({
|
|||||||
hasGameInvitation: false,
|
hasGameInvitation: false,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
connectionId: null,
|
||||||
aboutUrl: `${docsUrl}/${lang}/about`
|
aboutUrl: `/docs/${lang}/about`
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -13,8 +13,9 @@
|
|||||||
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
|
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
|
||||||
<ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch>
|
<ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch>
|
||||||
<ui-switch v-model="$store.state.settings.iLikeSushi" @change="onChangeILikeSushi">%i18n:common.i-like-sushi%</ui-switch>
|
<ui-switch v-model="$store.state.settings.iLikeSushi" @change="onChangeILikeSushi">%i18n:common.i-like-sushi%</ui-switch>
|
||||||
<ui-switch v-model="$store.state.settings.reversiBoardLabels" @change="onChangeReversiBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
|
|
||||||
<ui-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
|
<ui-switch v-model="$store.state.settings.disableAnimatedMfm" @change="onChangeDisableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
|
||||||
|
<ui-switch v-model="$store.state.settings.games.reversi.showBoardLabels" @change="onChangeReversiBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
|
||||||
|
<ui-switch v-model="$store.state.settings.games.reversi.useContrastStones" @change="onChangeUseContrastReversiStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div>%i18n:@timeline%</div>
|
<div>%i18n:@timeline%</div>
|
||||||
@ -189,7 +190,14 @@ export default Vue.extend({
|
|||||||
|
|
||||||
onChangeReversiBoardLabels(v) {
|
onChangeReversiBoardLabels(v) {
|
||||||
this.$store.dispatch('settings/set', {
|
this.$store.dispatch('settings/set', {
|
||||||
key: 'reversiBoardLabels',
|
key: 'games.reversi.showBoardLabels',
|
||||||
|
value: v
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onChangeUseContrastReversiStones(v) {
|
||||||
|
this.$store.dispatch('settings/set', {
|
||||||
|
key: 'games.reversi.useContrastStones',
|
||||||
value: v
|
value: v
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<a class="avatar">
|
<a class="avatar">
|
||||||
<img :src="user.avatarUrl" alt="avatar"/>
|
<img :src="user.avatarUrl" alt="avatar"/>
|
||||||
</a>
|
</a>
|
||||||
|
<mk-mute-button v-if="$store.state.i.id != user.id" :user="user"/>
|
||||||
<mk-follow-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
|
<mk-follow-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
@ -184,6 +185,9 @@ root(isDark)
|
|||||||
border 4px solid $bg
|
border 4px solid $bg
|
||||||
border-radius 12px
|
border-radius 12px
|
||||||
|
|
||||||
|
> .mk-mute-button
|
||||||
|
float right
|
||||||
|
|
||||||
> .mk-follow-button
|
> .mk-follow-button
|
||||||
float right
|
float right
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import Vuex from 'vuex';
|
import Vuex from 'vuex';
|
||||||
import createPersistedState from 'vuex-persistedstate';
|
import createPersistedState from 'vuex-persistedstate';
|
||||||
|
import * as nestedProperty from 'nested-property';
|
||||||
|
|
||||||
import MiOS from './mios';
|
import MiOS from './mios';
|
||||||
import { hostname } from './config';
|
import { hostname } from './config';
|
||||||
@ -22,7 +23,12 @@ const defaultSettings = {
|
|||||||
disableViaMobile: false,
|
disableViaMobile: false,
|
||||||
memo: null,
|
memo: null,
|
||||||
iLikeSushi: false,
|
iLikeSushi: false,
|
||||||
reversiBoardLabels: false
|
games: {
|
||||||
|
reversi: {
|
||||||
|
showBoardLabels: false,
|
||||||
|
useContrastStones: false
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultDeviceSettings = {
|
const defaultDeviceSettings = {
|
||||||
@ -125,7 +131,7 @@ export default (os: MiOS) => new Vuex.Store({
|
|||||||
|
|
||||||
mutations: {
|
mutations: {
|
||||||
set(state, x: { key: string; value: any }) {
|
set(state, x: { key: string; value: any }) {
|
||||||
state[x.key] = x.value;
|
nestedProperty.set(state, x.key, x.value);
|
||||||
},
|
},
|
||||||
|
|
||||||
setHome(state, data) {
|
setHome(state, data) {
|
||||||
|
@ -82,7 +82,7 @@ props:
|
|||||||
ja: "フォルダ"
|
ja: "フォルダ"
|
||||||
en: "The folder of this file"
|
en: "The folder of this file"
|
||||||
|
|
||||||
sensitive:
|
isSensitive:
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
optional: true
|
optional: true
|
||||||
desc:
|
desc:
|
||||||
|
10
src/index.ts
10
src/index.ts
@ -14,6 +14,7 @@ import * as portscanner from 'portscanner';
|
|||||||
import isRoot = require('is-root');
|
import isRoot = require('is-root');
|
||||||
import Xev from 'xev';
|
import Xev from 'xev';
|
||||||
import * as program from 'commander';
|
import * as program from 'commander';
|
||||||
|
import mongo from './db/mongodb';
|
||||||
|
|
||||||
import Logger from './misc/logger';
|
import Logger from './misc/logger';
|
||||||
import ProgressBar from './misc/cli/progressbar';
|
import ProgressBar from './misc/cli/progressbar';
|
||||||
@ -158,8 +159,13 @@ function checkMongoDb(config: Config) {
|
|||||||
const p = config.mongodb.pass ? encodeURIComponent(config.mongodb.pass) : null;
|
const p = config.mongodb.pass ? encodeURIComponent(config.mongodb.pass) : null;
|
||||||
const uri = `mongodb://${u && p ? `${u}:****@` : ''}${config.mongodb.host}:${config.mongodb.port}/${config.mongodb.db}`;
|
const uri = `mongodb://${u && p ? `${u}:****@` : ''}${config.mongodb.host}:${config.mongodb.port}/${config.mongodb.db}`;
|
||||||
mongoDBLogger.info(`Connecting to ${uri}`);
|
mongoDBLogger.info(`Connecting to ${uri}`);
|
||||||
require('./db/mongodb');
|
|
||||||
mongoDBLogger.succ('Connectivity confirmed');
|
mongo.then(() => {
|
||||||
|
mongoDBLogger.succ('Connectivity confirmed');
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
mongoDBLogger.error(err.message);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function spawnWorkers(limit: number) {
|
function spawnWorkers(limit: number) {
|
||||||
|
@ -27,10 +27,12 @@ export default class Replacer {
|
|||||||
let text = texts;
|
let text = texts;
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
|
path = path.replace('.ts', '');
|
||||||
|
|
||||||
if (text.hasOwnProperty(path)) {
|
if (text.hasOwnProperty(path)) {
|
||||||
text = text[path];
|
text = text[path];
|
||||||
} else {
|
} else {
|
||||||
if (this.lang === 'ja') console.warn(`path '${path}' not found`);
|
if (this.lang === 'ja-JP') console.warn(`path '${path}' not found`);
|
||||||
return key; // Fallback
|
return key; // Fallback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,10 +48,10 @@ export default class Replacer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
if (this.lang === 'ja') console.warn(`key '${key}' not found in '${path}'`);
|
if (this.lang === 'ja-JP') console.warn(`key '${key}' not found in '${path}'`);
|
||||||
return key; // Fallback
|
return key; // Fallback
|
||||||
} else if (typeof text !== 'string') {
|
} else if (typeof text !== 'string') {
|
||||||
if (this.lang === 'ja') console.warn(`key '${key}' is not string in '${path}'`);
|
if (this.lang === 'ja-JP') console.warn(`key '${key}' is not string in '${path}'`);
|
||||||
return key; // Fallback
|
return key; // Fallback
|
||||||
} else {
|
} else {
|
||||||
return text;
|
return text;
|
||||||
|
@ -10,6 +10,8 @@ export interface IStats {
|
|||||||
|
|
||||||
date: Date;
|
date: Date;
|
||||||
|
|
||||||
|
span: 'day' | 'hour';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ユーザーに関する統計
|
* ユーザーに関する統計
|
||||||
*/
|
*/
|
||||||
|
@ -118,6 +118,7 @@ export interface IRemoteUser extends IUserBase {
|
|||||||
publicKeyPem: string;
|
publicKeyPem: string;
|
||||||
};
|
};
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
isAdmin: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IUser = ILocalUser | IRemoteUser;
|
export type IUser = ILocalUser | IRemoteUser;
|
||||||
|
@ -131,7 +131,8 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs
|
|||||||
endpoints: person.endpoints,
|
endpoints: person.endpoints,
|
||||||
uri: person.id,
|
uri: person.id,
|
||||||
url: person.url,
|
url: person.url,
|
||||||
isBot
|
isBot: isBot,
|
||||||
|
isCat: (person as any).isCat === true ? true : false
|
||||||
}) as IRemoteUser;
|
}) as IRemoteUser;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// duplicate key error
|
// duplicate key error
|
||||||
@ -262,7 +263,8 @@ export async function updatePerson(value: string | IObject, resolver?: Resolver)
|
|||||||
notesCount,
|
notesCount,
|
||||||
name: person.name,
|
name: person.name,
|
||||||
url: person.url,
|
url: person.url,
|
||||||
endpoints: person.endpoints
|
endpoints: person.endpoints,
|
||||||
|
isCat: (person as any).isCat === true ? true : false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ export default async (user: ILocalUser) => {
|
|||||||
icon: user.avatarId && renderImage(avatar),
|
icon: user.avatarId && renderImage(avatar),
|
||||||
image: user.bannerId && renderImage(banner),
|
image: user.bannerId && renderImage(banner),
|
||||||
manuallyApprovesFollowers: user.isLocked,
|
manuallyApprovesFollowers: user.isLocked,
|
||||||
publicKey: renderKey(user)
|
publicKey: renderKey(user),
|
||||||
|
isCat: user.isCat
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,7 @@ export default async (username: string, _host: string, option?: any): Promise<IU
|
|||||||
const host = toUnicode(hostAscii);
|
const host = toUnicode(hostAscii);
|
||||||
|
|
||||||
if (config.host == host) {
|
if (config.host == host) {
|
||||||
return await User.findOne({ usernameLower });
|
return await User.findOne({ usernameLower, host: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
let user = await User.findOne({ usernameLower, host }, option);
|
let user = await User.findOne({ usernameLower, host }, option);
|
||||||
|
@ -41,10 +41,20 @@ function inbox(ctx: Router.IRouterContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isActivityPubReq(ctx: Router.IRouterContext) {
|
function isActivityPubReq(ctx: Router.IRouterContext) {
|
||||||
|
ctx.response.vary('Accept');
|
||||||
const accepted = ctx.accepts('html', 'application/activity+json', 'application/ld+json');
|
const accepted = ctx.accepts('html', 'application/activity+json', 'application/ld+json');
|
||||||
return ['application/activity+json', 'application/ld+json'].includes(accepted as string);
|
return ['application/activity+json', 'application/ld+json'].includes(accepted as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setResponseType(ctx: Router.IRouterContext) {
|
||||||
|
const accpet = ctx.accepts('application/activity+json', 'application/ld+json');
|
||||||
|
if (accpet === 'application/ld+json') {
|
||||||
|
ctx.response.type = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8';
|
||||||
|
} else {
|
||||||
|
ctx.response.type = 'application/activity+json; charset=utf-8';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// inbox
|
// inbox
|
||||||
router.post('/inbox', json(), inbox);
|
router.post('/inbox', json(), inbox);
|
||||||
router.post('/users/:user/inbox', json(), inbox);
|
router.post('/users/:user/inbox', json(), inbox);
|
||||||
@ -54,7 +64,8 @@ router.get('/notes/:note', async (ctx, next) => {
|
|||||||
if (!isActivityPubReq(ctx)) return await next();
|
if (!isActivityPubReq(ctx)) return await next();
|
||||||
|
|
||||||
const note = await Note.findOne({
|
const note = await Note.findOne({
|
||||||
_id: new mongo.ObjectID(ctx.params.note)
|
_id: new mongo.ObjectID(ctx.params.note),
|
||||||
|
$or: [ { visibility: 'public' }, { visibility: 'home' } ]
|
||||||
});
|
});
|
||||||
|
|
||||||
if (note === null) {
|
if (note === null) {
|
||||||
@ -62,7 +73,8 @@ router.get('/notes/:note', async (ctx, next) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = pack(await renderNote(note));
|
ctx.body = pack(await renderNote(note, false));
|
||||||
|
setResponseType(ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
// outbox
|
// outbox
|
||||||
@ -90,6 +102,7 @@ router.get('/users/:user/publickey', async ctx => {
|
|||||||
|
|
||||||
if (isLocalUser(user)) {
|
if (isLocalUser(user)) {
|
||||||
ctx.body = pack(renderKey(user));
|
ctx.body = pack(renderKey(user));
|
||||||
|
setResponseType(ctx);
|
||||||
} else {
|
} else {
|
||||||
ctx.status = 400;
|
ctx.status = 400;
|
||||||
}
|
}
|
||||||
@ -103,6 +116,7 @@ async function userInfo(ctx: Router.IRouterContext, user: IUser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.body = pack(await renderPerson(user as ILocalUser));
|
ctx.body = pack(await renderPerson(user as ILocalUser));
|
||||||
|
setResponseType(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
router.get('/users/:user', async ctx => {
|
router.get('/users/:user', async ctx => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import * as Koa from 'koa';
|
import * as Router from 'koa-router';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import $ from 'cafy'; import ID from '../../misc/cafy-id';
|
import $ from 'cafy'; import ID from '../../misc/cafy-id';
|
||||||
import User from '../../models/user';
|
import User from '../../models/user';
|
||||||
@ -8,8 +8,9 @@ import pack from '../../remote/activitypub/renderer';
|
|||||||
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
|
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
|
||||||
import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
|
import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
|
||||||
import renderFollowUser from '../../remote/activitypub/renderer/follow-user';
|
import renderFollowUser from '../../remote/activitypub/renderer/follow-user';
|
||||||
|
import { setResponseType } from '../activitypub';
|
||||||
|
|
||||||
export default async (ctx: Koa.Context) => {
|
export default async (ctx: Router.IRouterContext) => {
|
||||||
const userId = new mongo.ObjectID(ctx.params.user);
|
const userId = new mongo.ObjectID(ctx.params.user);
|
||||||
|
|
||||||
// Get 'cursor' parameter
|
// Get 'cursor' parameter
|
||||||
@ -72,9 +73,11 @@ export default async (ctx: Koa.Context) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
ctx.body = pack(rendered);
|
ctx.body = pack(rendered);
|
||||||
|
setResponseType(ctx);
|
||||||
} else {
|
} else {
|
||||||
// index page
|
// index page
|
||||||
const rendered = renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`, null);
|
const rendered = renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`, null);
|
||||||
ctx.body = pack(rendered);
|
ctx.body = pack(rendered);
|
||||||
|
setResponseType(ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import * as Koa from 'koa';
|
import * as Router from 'koa-router';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import $ from 'cafy'; import ID from '../../misc/cafy-id';
|
import $ from 'cafy'; import ID from '../../misc/cafy-id';
|
||||||
import User from '../../models/user';
|
import User from '../../models/user';
|
||||||
@ -8,8 +8,9 @@ import pack from '../../remote/activitypub/renderer';
|
|||||||
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
|
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
|
||||||
import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
|
import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
|
||||||
import renderFollowUser from '../../remote/activitypub/renderer/follow-user';
|
import renderFollowUser from '../../remote/activitypub/renderer/follow-user';
|
||||||
|
import { setResponseType } from '../activitypub';
|
||||||
|
|
||||||
export default async (ctx: Koa.Context) => {
|
export default async (ctx: Router.IRouterContext) => {
|
||||||
const userId = new mongo.ObjectID(ctx.params.user);
|
const userId = new mongo.ObjectID(ctx.params.user);
|
||||||
|
|
||||||
// Get 'cursor' parameter
|
// Get 'cursor' parameter
|
||||||
@ -72,9 +73,11 @@ export default async (ctx: Koa.Context) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
ctx.body = pack(rendered);
|
ctx.body = pack(rendered);
|
||||||
|
setResponseType(ctx);
|
||||||
} else {
|
} else {
|
||||||
// index page
|
// index page
|
||||||
const rendered = renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`, null);
|
const rendered = renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`, null);
|
||||||
ctx.body = pack(rendered);
|
ctx.body = pack(rendered);
|
||||||
|
setResponseType(ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import * as mongo from 'mongodb';
|
import * as mongo from 'mongodb';
|
||||||
import * as Koa from 'koa';
|
import * as Router from 'koa-router';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import $ from 'cafy'; import ID from '../../misc/cafy-id';
|
import $ from 'cafy'; import ID from '../../misc/cafy-id';
|
||||||
import User from '../../models/user';
|
import User from '../../models/user';
|
||||||
import pack from '../../remote/activitypub/renderer';
|
import pack from '../../remote/activitypub/renderer';
|
||||||
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
|
import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-collection';
|
||||||
import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
|
import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
|
||||||
|
import { setResponseType } from '../activitypub';
|
||||||
|
|
||||||
import Note from '../../models/note';
|
import Note from '../../models/note';
|
||||||
import renderNote from '../../remote/activitypub/renderer/note';
|
import renderNote from '../../remote/activitypub/renderer/note';
|
||||||
|
|
||||||
export default async (ctx: Koa.Context) => {
|
export default async (ctx: Router.IRouterContext) => {
|
||||||
const userId = new mongo.ObjectID(ctx.params.user);
|
const userId = new mongo.ObjectID(ctx.params.user);
|
||||||
|
|
||||||
// Get 'sinceId' parameter
|
// Get 'sinceId' parameter
|
||||||
@ -83,7 +84,7 @@ export default async (ctx: Koa.Context) => {
|
|||||||
|
|
||||||
if (sinceId) notes.reverse();
|
if (sinceId) notes.reverse();
|
||||||
|
|
||||||
const renderedNotes = await Promise.all(notes.map(note => renderNote(note)));
|
const renderedNotes = await Promise.all(notes.map(note => renderNote(note, false)));
|
||||||
const rendered = renderOrderedCollectionPage(
|
const rendered = renderOrderedCollectionPage(
|
||||||
`${partOf}?page=true${sinceId ? `&since_id=${sinceId}` : ''}${untilId ? `&until_id=${untilId}` : ''}`,
|
`${partOf}?page=true${sinceId ? `&since_id=${sinceId}` : ''}${untilId ? `&until_id=${untilId}` : ''}`,
|
||||||
user.notesCount, renderedNotes, partOf,
|
user.notesCount, renderedNotes, partOf,
|
||||||
@ -92,6 +93,7 @@ export default async (ctx: Koa.Context) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
ctx.body = pack(rendered);
|
ctx.body = pack(rendered);
|
||||||
|
setResponseType(ctx);
|
||||||
} else {
|
} else {
|
||||||
// index page
|
// index page
|
||||||
const rendered = renderOrderedCollection(partOf, user.notesCount,
|
const rendered = renderOrderedCollection(partOf, user.notesCount,
|
||||||
@ -99,5 +101,6 @@ export default async (ctx: Koa.Context) => {
|
|||||||
`${partOf}?page=true&since_id=000000000000000000000000`
|
`${partOf}?page=true&since_id=000000000000000000000000`
|
||||||
);
|
);
|
||||||
ctx.body = pack(rendered);
|
ctx.body = pack(rendered);
|
||||||
|
setResponseType(ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
import limitter from './limitter';
|
import limitter from './limitter';
|
||||||
import { IUser, isLocalUser } from '../../models/user';
|
import { IUser } from '../../models/user';
|
||||||
import { IApp } from '../../models/app';
|
import { IApp } from '../../models/app';
|
||||||
import endpoints from './endpoints';
|
import endpoints from './endpoints';
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ export default (endpoint: string, user: IUser, app: IApp, data: any, file?: any)
|
|||||||
return rej('YOUR_ACCOUNT_HAS_BEEN_SUSPENDED');
|
return rej('YOUR_ACCOUNT_HAS_BEEN_SUSPENDED');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ep.meta.requireAdmin && !(isLocalUser(user) && user.isAdmin)) {
|
if (ep.meta.requireAdmin && !user.isAdmin) {
|
||||||
return rej('YOU_ARE_NOT_ADMIN');
|
return rej('YOU_ARE_NOT_ADMIN');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ export default (params: any) => new Promise(async (res, rej) => {
|
|||||||
const d = now.getDate();
|
const d = now.getDate();
|
||||||
|
|
||||||
const stats = await Stats.find({
|
const stats = await Stats.find({
|
||||||
|
span: 'day',
|
||||||
date: {
|
date: {
|
||||||
$gt: new Date(y - 1, m, d)
|
$gt: new Date(y - 1, m, d)
|
||||||
}
|
}
|
||||||
@ -44,6 +45,7 @@ export default (params: any) => new Promise(async (res, rej) => {
|
|||||||
} else {
|
} else {
|
||||||
chart.unshift({
|
chart.unshift({
|
||||||
date: day,
|
date: day,
|
||||||
|
span: 'day',
|
||||||
users: {
|
users: {
|
||||||
local: {
|
local: {
|
||||||
total: 0,
|
total: 0,
|
||||||
|
@ -34,6 +34,10 @@ export default (params: any) => new Promise(async (res, rej) => {
|
|||||||
return rej('user not found');
|
return rej('user not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (user.isAdmin) {
|
||||||
|
return rej('cannot suspend admin');
|
||||||
|
}
|
||||||
|
|
||||||
await User.findOneAndUpdate({
|
await User.findOneAndUpdate({
|
||||||
_id: user._id
|
_id: user._id
|
||||||
}, {
|
}, {
|
||||||
|
37
src/server/api/endpoints/admin/update-meta.ts
Normal file
37
src/server/api/endpoints/admin/update-meta.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import $ from 'cafy';
|
||||||
|
import Meta from '../../../../models/meta';
|
||||||
|
import getParams from '../../get-params';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
desc: {
|
||||||
|
ja: 'インスタンスの設定を更新します。'
|
||||||
|
},
|
||||||
|
|
||||||
|
requireCredential: true,
|
||||||
|
requireAdmin: true,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
disableRegistration: $.bool.optional.nullable.note({
|
||||||
|
desc: {
|
||||||
|
ja: '招待制か否か'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (params: any) => new Promise(async (res, rej) => {
|
||||||
|
const [ps, psErr] = getParams(meta, params);
|
||||||
|
if (psErr) return rej(psErr);
|
||||||
|
|
||||||
|
const set = {} as any;
|
||||||
|
|
||||||
|
if (ps.disableRegistration === true || ps.disableRegistration === false) {
|
||||||
|
set.disableRegistration = ps.disableRegistration;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Meta.update({}, {
|
||||||
|
$set: set
|
||||||
|
}, { upsert: true });
|
||||||
|
|
||||||
|
res();
|
||||||
|
});
|
@ -34,9 +34,12 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
|
|||||||
const sort = {
|
const sort = {
|
||||||
_id: -1
|
_id: -1
|
||||||
};
|
};
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
'metadata.userId': user._id
|
'metadata.userId': user._id,
|
||||||
|
'metadata.deletedAt': { $exists: false }
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
if (sinceId) {
|
if (sinceId) {
|
||||||
sort._id = 1;
|
sort._id = 1;
|
||||||
query._id = {
|
query._id = {
|
||||||
@ -47,6 +50,7 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
|
|||||||
$lt: untilId
|
$lt: untilId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type) {
|
if (type) {
|
||||||
query.contentType = new RegExp(`^${type.replace(/\*/g, '.+?')}$`);
|
query.contentType = new RegExp(`^${type.replace(/\*/g, '.+?')}$`);
|
||||||
}
|
}
|
||||||
@ -59,6 +63,5 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Serialize
|
// Serialize
|
||||||
res(await Promise.all(files.map(async file =>
|
res(await Promise.all(files.map(file => pack(file))));
|
||||||
await pack(file))));
|
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,11 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
|
|||||||
return rej('followee not found');
|
return rej('followee not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await cancelFollowRequest(followee, user);
|
try {
|
||||||
|
await cancelFollowRequest(followee, user);
|
||||||
|
} catch (e) {
|
||||||
|
return rej(e);
|
||||||
|
}
|
||||||
|
|
||||||
// Send response
|
// Send response
|
||||||
res(await pack(followee._id, user));
|
res(await pack(followee._id, user));
|
||||||
|
@ -12,6 +12,7 @@ export default async (ctx: Koa.Context) => {
|
|||||||
ctx.set('Access-Control-Allow-Credentials', 'true');
|
ctx.set('Access-Control-Allow-Credentials', 'true');
|
||||||
|
|
||||||
const body = ctx.request.body as any;
|
const body = ctx.request.body as any;
|
||||||
|
// See: https://github.com/syuilo/misskey/issues/2384
|
||||||
const username = body['username'] || body['x'];
|
const username = body['username'] || body['x'];
|
||||||
const password = body['password'] || body['y'];
|
const password = body['password'] || body['y'];
|
||||||
const token = body['token'];
|
const token = body['token'];
|
||||||
@ -63,7 +64,7 @@ export default async (ctx: Koa.Context) => {
|
|||||||
if (verified) {
|
if (verified) {
|
||||||
signin(ctx, user);
|
signin(ctx, user);
|
||||||
} else {
|
} else {
|
||||||
ctx.throw(400, {
|
ctx.throw(403, {
|
||||||
error: 'invalid token'
|
error: 'invalid token'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -71,7 +72,7 @@ export default async (ctx: Koa.Context) => {
|
|||||||
signin(ctx, user);
|
signin(ctx, user);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.throw(400, {
|
ctx.throw(403, {
|
||||||
error: 'incorrect password'
|
error: 'incorrect password'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,13 @@ export default async function(
|
|||||||
subscriber: Xev,
|
subscriber: Xev,
|
||||||
user: IUser
|
user: IUser
|
||||||
) {
|
) {
|
||||||
|
const mute = await Mute.find({ muterId: user._id });
|
||||||
|
const mutedUserIds = mute.map(m => m.muteeId.toString());
|
||||||
|
|
||||||
// Subscribe stream
|
// Subscribe stream
|
||||||
subscriber.on('hybrid-timeline', onEvent);
|
subscriber.on('hybrid-timeline', onEvent);
|
||||||
subscriber.on(`hybrid-timeline:${user._id}`, onEvent);
|
subscriber.on(`hybrid-timeline:${user._id}`, onEvent);
|
||||||
|
|
||||||
const mute = await Mute.find({ muterId: user._id });
|
|
||||||
const mutedUserIds = mute.map(m => m.muteeId.toString());
|
|
||||||
|
|
||||||
async function onEvent(note: any) {
|
async function onEvent(note: any) {
|
||||||
//#region 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
//#region 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する
|
||||||
if (mutedUserIds.indexOf(note.userId) != -1) {
|
if (mutedUserIds.indexOf(note.userId) != -1) {
|
||||||
|
@ -12,6 +12,15 @@ export default async function(followee: IUser, follower: IUser) {
|
|||||||
deliver(follower as ILocalUser, content, followee.inbox);
|
deliver(follower as ILocalUser, content, followee.inbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const request = await FollowRequest.findOne({
|
||||||
|
followeeId: followee._id,
|
||||||
|
followerId: follower._id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (request == null) {
|
||||||
|
throw 'request not found';
|
||||||
|
}
|
||||||
|
|
||||||
await FollowRequest.remove({
|
await FollowRequest.remove({
|
||||||
followeeId: followee._id,
|
followeeId: followee._id,
|
||||||
followerId: follower._id
|
followerId: follower._id
|
||||||
|
@ -5,89 +5,46 @@ import { IDriveFile } from '../models/drive-file';
|
|||||||
|
|
||||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||||
|
|
||||||
async function getTodayStats(): Promise<IStats> {
|
async function getCurrentStats(span: 'day' | 'hour'): Promise<IStats> {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const y = now.getFullYear();
|
const y = now.getFullYear();
|
||||||
const m = now.getMonth();
|
const m = now.getMonth();
|
||||||
const d = now.getDate();
|
const d = now.getDate();
|
||||||
const today = new Date(y, m, d);
|
const h = now.getHours();
|
||||||
|
|
||||||
// 今日の統計
|
const current =
|
||||||
const todayStats = await Stats.findOne({
|
span == 'day' ? new Date(y, m, d) :
|
||||||
date: today
|
span == 'hour' ? new Date(y, m, d, h) :
|
||||||
|
null;
|
||||||
|
|
||||||
|
// 現在(今日または今のHour)の統計
|
||||||
|
const currentStats = await Stats.findOne({
|
||||||
|
span: span,
|
||||||
|
date: current
|
||||||
});
|
});
|
||||||
|
|
||||||
// 日付が変わってから、初めてのチャート更新なら
|
if (currentStats) {
|
||||||
if (todayStats == null) {
|
return currentStats;
|
||||||
|
} else {
|
||||||
|
// 集計期間が変わってから、初めてのチャート更新なら
|
||||||
// 最も最近の統計を持ってくる
|
// 最も最近の統計を持ってくる
|
||||||
|
// * 例えば集計期間が「日」である場合で考えると、
|
||||||
// * 昨日何もチャートを更新するような出来事がなかった場合は、
|
// * 昨日何もチャートを更新するような出来事がなかった場合は、
|
||||||
// 統計がそもそも作られずドキュメントが存在しないということがあり得るため、
|
// * 統計がそもそも作られずドキュメントが存在しないということがあり得るため、
|
||||||
// 「昨日の」と決め打ちせずに「もっとも最近の」とします
|
// * 「昨日の」と決め打ちせずに「もっとも最近の」とします
|
||||||
const mostRecentStats = await Stats.findOne({}, {
|
const mostRecentStats = await Stats.findOne({
|
||||||
|
span: span
|
||||||
|
}, {
|
||||||
sort: {
|
sort: {
|
||||||
date: -1
|
date: -1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 統計が存在しなかったら
|
if (mostRecentStats) {
|
||||||
// * Misskeyインスタンスを建てて初めてのチャート更新時など
|
// 現在の統計を初期挿入
|
||||||
if (mostRecentStats == null) {
|
|
||||||
// 空の統計を作成
|
|
||||||
const data: Omit<IStats, '_id'> = {
|
const data: Omit<IStats, '_id'> = {
|
||||||
date: today,
|
span: span,
|
||||||
users: {
|
date: current,
|
||||||
local: {
|
|
||||||
total: 0,
|
|
||||||
diff: 0
|
|
||||||
},
|
|
||||||
remote: {
|
|
||||||
total: 0,
|
|
||||||
diff: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
notes: {
|
|
||||||
local: {
|
|
||||||
total: 0,
|
|
||||||
diff: 0,
|
|
||||||
diffs: {
|
|
||||||
normal: 0,
|
|
||||||
reply: 0,
|
|
||||||
renote: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
remote: {
|
|
||||||
total: 0,
|
|
||||||
diff: 0,
|
|
||||||
diffs: {
|
|
||||||
normal: 0,
|
|
||||||
reply: 0,
|
|
||||||
renote: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
drive: {
|
|
||||||
local: {
|
|
||||||
totalCount: 0,
|
|
||||||
totalSize: 0,
|
|
||||||
diffCount: 0,
|
|
||||||
diffSize: 0
|
|
||||||
},
|
|
||||||
remote: {
|
|
||||||
totalCount: 0,
|
|
||||||
totalSize: 0,
|
|
||||||
diffCount: 0,
|
|
||||||
diffSize: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const stats = await Stats.insert(data);
|
|
||||||
|
|
||||||
return stats;
|
|
||||||
} else {
|
|
||||||
// 今日の統計を初期挿入
|
|
||||||
const data: Omit<IStats, '_id'> = {
|
|
||||||
date: today,
|
|
||||||
users: {
|
users: {
|
||||||
local: {
|
local: {
|
||||||
total: mostRecentStats.users.local.total,
|
total: mostRecentStats.users.local.total,
|
||||||
@ -136,20 +93,83 @@ async function getTodayStats(): Promise<IStats> {
|
|||||||
|
|
||||||
const stats = await Stats.insert(data);
|
const stats = await Stats.insert(data);
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
} else {
|
||||||
|
// 統計が存在しなかったら
|
||||||
|
// * Misskeyインスタンスを建てて初めてのチャート更新時など
|
||||||
|
|
||||||
|
// 空の統計を作成
|
||||||
|
const emptyStat: Omit<IStats, '_id'> = {
|
||||||
|
span: span,
|
||||||
|
date: current,
|
||||||
|
users: {
|
||||||
|
local: {
|
||||||
|
total: 0,
|
||||||
|
diff: 0
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
total: 0,
|
||||||
|
diff: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
notes: {
|
||||||
|
local: {
|
||||||
|
total: 0,
|
||||||
|
diff: 0,
|
||||||
|
diffs: {
|
||||||
|
normal: 0,
|
||||||
|
reply: 0,
|
||||||
|
renote: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
total: 0,
|
||||||
|
diff: 0,
|
||||||
|
diffs: {
|
||||||
|
normal: 0,
|
||||||
|
reply: 0,
|
||||||
|
renote: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
drive: {
|
||||||
|
local: {
|
||||||
|
totalCount: 0,
|
||||||
|
totalSize: 0,
|
||||||
|
diffCount: 0,
|
||||||
|
diffSize: 0
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
totalCount: 0,
|
||||||
|
totalSize: 0,
|
||||||
|
diffCount: 0,
|
||||||
|
diffSize: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const stats = await Stats.insert(emptyStat);
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return todayStats;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function update(inc: any) {
|
function update(inc: any) {
|
||||||
const stats = await getTodayStats();
|
getCurrentStats('day').then(stats => {
|
||||||
|
Stats.findOneAndUpdate({
|
||||||
|
_id: stats._id
|
||||||
|
}, {
|
||||||
|
$inc: inc
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
await Stats.findOneAndUpdate({
|
getCurrentStats('hour').then(stats => {
|
||||||
_id: stats._id
|
Stats.findOneAndUpdate({
|
||||||
}, {
|
_id: stats._id
|
||||||
$inc: inc
|
}, {
|
||||||
|
$inc: inc
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ import I18nReplacer from './src/misc/i18n';
|
|||||||
import { pattern as i18nPattern, replacement as i18nReplacement } from './webpack/i18n';
|
import { pattern as i18nPattern, replacement as i18nReplacement } from './webpack/i18n';
|
||||||
import { pattern as faPattern, replacement as faReplacement } from './src/misc/fa';
|
import { pattern as faPattern, replacement as faReplacement } from './src/misc/fa';
|
||||||
const constants = require('./src/const.json');
|
const constants = require('./src/const.json');
|
||||||
import { licenseHtml } from './src/misc/license';
|
|
||||||
|
|
||||||
const locales = require('./locales');
|
const locales = require('./locales');
|
||||||
const meta = require('./package.json');
|
const meta = require('./package.json');
|
||||||
@ -74,8 +73,7 @@ const consts = {
|
|||||||
_VERSION_: version,
|
_VERSION_: version,
|
||||||
_CODENAME_: codename,
|
_CODENAME_: codename,
|
||||||
_LANG_: '%lang%',
|
_LANG_: '%lang%',
|
||||||
_LANGS_: Object.keys(locales).map(l => [l, locales[l].meta.lang]),
|
_LANGS_: Object.keys(locales).map(l => [l, locales[l].meta.lang])
|
||||||
_LICENSE_: licenseHtml
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const _consts: { [ key: string ]: any } = {};
|
const _consts: { [ key: string ]: any } = {};
|
||||||
|
Reference in New Issue
Block a user