ディレクトリ再編
This commit is contained in:
parent
cb924ff92b
commit
85d471efbb
45 changed files with 204 additions and 41 deletions
70
src/backend/functions/format.ts
Normal file
70
src/backend/functions/format.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
import { config } from '../../config';
|
||||
import { User } from '../models/entities/user';
|
||||
import { Score } from '../../common/types/score';
|
||||
|
||||
export const defaultTemplate = `昨日のMisskeyの活動は
|
||||
|
||||
ノート: {notesCount}({notesDelta})
|
||||
フォロー : {followingCount}({followingDelta})
|
||||
フォロワー :{followersCount}({followersDelta})
|
||||
|
||||
でした。
|
||||
{url}`;
|
||||
|
||||
export type Variable = {
|
||||
description?: string;
|
||||
replace?: string | ((score: Score, user: User) => string);
|
||||
};
|
||||
|
||||
export const variables: Record<string, Variable> = {
|
||||
notesCount: {
|
||||
description: 'ノート数',
|
||||
replace: (score) => String(score.notesCount),
|
||||
},
|
||||
followingCount: {
|
||||
description: 'フォロー数',
|
||||
replace: (score) => String(score.followingCount),
|
||||
},
|
||||
followersCount: {
|
||||
description: 'フォロワー数',
|
||||
replace: (score) => String(score.followersCount),
|
||||
},
|
||||
notesDelta: {
|
||||
description: '昨日とのノート数の差',
|
||||
replace: (score) => String(score.notesDelta),
|
||||
},
|
||||
followingDelta: {
|
||||
description: '昨日とのフォロー数の差',
|
||||
replace: (score) => String(score.followingDelta),
|
||||
},
|
||||
followersDelta: {
|
||||
description: '昨日とのフォロワー数の差',
|
||||
replace: (score) => String(score.followersDelta),
|
||||
},
|
||||
url: {
|
||||
description: 'みす廃アラートのURL',
|
||||
replace: config.url,
|
||||
},
|
||||
username: {
|
||||
description: 'ユーザー名',
|
||||
replace: (_, user) => String(user.username),
|
||||
},
|
||||
host: {
|
||||
description: '所属するインスタンスのホスト名',
|
||||
replace: (_, user) => String(user.host),
|
||||
},
|
||||
rating: {
|
||||
description: 'みす廃レート',
|
||||
replace: (_, user) => String(user.rating),
|
||||
},
|
||||
};
|
||||
|
||||
const variableRegex = /\{([a-zA-Z0-9_]+?)\}/g;
|
||||
|
||||
export const format = (score: Score, user: User): string => {
|
||||
const template = user.template || defaultTemplate;
|
||||
return template.replace(variableRegex, (m, name) => {
|
||||
const v = variables[name];
|
||||
return !v || !v.replace ? m : typeof v.replace === 'function' ? v.replace(score, user) : v.replace;
|
||||
}) + '\n\n#misshaialert';
|
||||
};
|
13
src/backend/functions/gen-token.ts
Normal file
13
src/backend/functions/gen-token.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import rndstr from 'rndstr';
|
||||
import { UsedToken } from '../models/entities/used-token';
|
||||
import { UsedTokens } from '../models';
|
||||
|
||||
export const genToken = async (): Promise<string> => {
|
||||
let used: UsedToken | undefined = undefined;
|
||||
let token: string;
|
||||
do {
|
||||
token = rndstr(32);
|
||||
used = await UsedTokens.findOne({ token });
|
||||
} while (used !== undefined);
|
||||
return token;
|
||||
};
|
19
src/backend/functions/get-scores.ts
Normal file
19
src/backend/functions/get-scores.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { User } from '../models/entities/user';
|
||||
import { Score } from '../../common/types/score';
|
||||
import { api } from '../services/misskey';
|
||||
import { toSignedString } from './to-signed-string';
|
||||
|
||||
export const getScores = async (user: User): Promise<Score> => {
|
||||
const miUser = await api<Record<string, number>>(user.host, 'users/show', { username: user.username }, user.token);
|
||||
if (miUser.error) {
|
||||
throw miUser.error;
|
||||
}
|
||||
return {
|
||||
notesCount: miUser.notesCount,
|
||||
followingCount: miUser.followingCount,
|
||||
followersCount: miUser.followersCount,
|
||||
notesDelta: toSignedString(miUser.notesCount - user.prevNotesCount),
|
||||
followingDelta: toSignedString(miUser.followingCount - user.prevFollowingCount),
|
||||
followersDelta: toSignedString(miUser.followersCount - user.prevFollowersCount),
|
||||
};
|
||||
};
|
14
src/backend/functions/ranking.ts
Normal file
14
src/backend/functions/ranking.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Users } from '../models';
|
||||
import { User } from '../models/entities/user';
|
||||
|
||||
export const getRanking = async (limit: number | null = 10): Promise<User[]> => {
|
||||
const query = Users.createQueryBuilder('user')
|
||||
.where('"user"."bannedFromRanking" IS NOT TRUE')
|
||||
.orderBy('"user".rating', 'DESC');
|
||||
|
||||
if (limit !== null) {
|
||||
query.limit(limit);
|
||||
}
|
||||
|
||||
return await query.getMany();
|
||||
};
|
1
src/backend/functions/to-signed-string.ts
Normal file
1
src/backend/functions/to-signed-string.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const toSignedString = (num: number): string => num < 0 ? num.toString() : '+' + num;
|
13
src/backend/functions/update-rating.ts
Normal file
13
src/backend/functions/update-rating.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import dayjs from 'dayjs';
|
||||
|
||||
import { User } from '../models/entities/user';
|
||||
import { updateUser } from './users';
|
||||
import { MiUser } from './update-score';
|
||||
|
||||
export const updateRating = async (user: User, miUser: MiUser): Promise<void> => {
|
||||
const elapsedDays = dayjs().diff(dayjs(miUser.createdAt), 'd') + 1;
|
||||
await updateUser(user.username, user.host, {
|
||||
prevRating: user.rating,
|
||||
rating: miUser.notesCount / elapsedDays,
|
||||
});
|
||||
};
|
17
src/backend/functions/update-score.ts
Normal file
17
src/backend/functions/update-score.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { User } from '../models/entities/user';
|
||||
import { updateUser } from './users';
|
||||
|
||||
export type MiUser = {
|
||||
notesCount: number,
|
||||
followingCount: number,
|
||||
followersCount: number,
|
||||
createdAt: string,
|
||||
};
|
||||
|
||||
export const updateScore = async (user: User, miUser: MiUser): Promise<void> => {
|
||||
await updateUser(user.username, user.host, {
|
||||
prevNotesCount: miUser.notesCount ?? 0,
|
||||
prevFollowingCount: miUser.followingCount ?? 0,
|
||||
prevFollowersCount: miUser.followersCount ?? 0,
|
||||
});
|
||||
};
|
44
src/backend/functions/users.ts
Normal file
44
src/backend/functions/users.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { User } from '../models/entities/user';
|
||||
import { Users } from '../models';
|
||||
import { DeepPartial } from 'typeorm';
|
||||
import { genToken } from './gen-token';
|
||||
import pick from 'object.pick';
|
||||
|
||||
export const getUser = (username: string, host: string): Promise<User | undefined> => {
|
||||
return Users.findOne({ username, host });
|
||||
};
|
||||
|
||||
export const updateUsersMisshaiToken = async (user: User | User['id']): Promise<string> => {
|
||||
const u = typeof user === 'number'
|
||||
? user
|
||||
: user.id;
|
||||
|
||||
const misshaiToken = await genToken();
|
||||
Users.update(u, { misshaiToken });
|
||||
return misshaiToken;
|
||||
};
|
||||
|
||||
export const getUserByMisshaiToken = (token: string): Promise<User | undefined> => {
|
||||
return Users.findOne({ misshaiToken: token });
|
||||
};
|
||||
|
||||
export const upsertUser = async (username: string, host: string, token: string): Promise<void> => {
|
||||
const u = await getUser(username, host);
|
||||
if (u) {
|
||||
await Users.update(u.id, { token });
|
||||
} else {
|
||||
await Users.insert({ username, host, token });
|
||||
}
|
||||
};
|
||||
|
||||
export const updateUser = async (username: string, host: string, record: DeepPartial<User>): Promise<void> => {
|
||||
await Users.update({ username, host }, record);
|
||||
};
|
||||
|
||||
export const deleteUser = async (username: string, host: string): Promise<void> => {
|
||||
await Users.delete({ username, host });
|
||||
};
|
||||
|
||||
export const getUserCount = (): Promise<number> => {
|
||||
return Users.count();
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue