diff --git a/src/models/entities/user-keypair.ts b/src/models/entities/user-keypair.ts
index 808985f473..603321d758 100644
--- a/src/models/entities/user-keypair.ts
+++ b/src/models/entities/user-keypair.ts
@@ -22,4 +22,12 @@ export class UserKeypair {
length: 4096,
})
public privateKey: string;
+
+ constructor(data: Partial) {
+ if (data == null) return;
+
+ for (const [k, v] of Object.entries(data)) {
+ (this as any)[k] = v;
+ }
+ }
}
diff --git a/src/models/entities/user-profile.ts b/src/models/entities/user-profile.ts
index 421d17c59e..a2d7b8d2c2 100644
--- a/src/models/entities/user-profile.ts
+++ b/src/models/entities/user-profile.ts
@@ -39,6 +39,12 @@ export class UserProfile {
value: string;
}[];
+ @Column('varchar', {
+ length: 512, nullable: true,
+ comment: 'Remote URL of the user.'
+ })
+ public url: string | null;
+
@Column('varchar', {
length: 128, nullable: true,
comment: 'The email address of the User.'
@@ -192,4 +198,12 @@ export class UserProfile {
})
public userHost: string | null;
//#endregion
+
+ constructor(data: Partial) {
+ if (data == null) return;
+
+ for (const [k, v] of Object.entries(data)) {
+ (this as any)[k] = v;
+ }
+ }
}
diff --git a/src/models/entities/user-publickey.ts b/src/models/entities/user-publickey.ts
index 26b694407d..21edc3e9e2 100644
--- a/src/models/entities/user-publickey.ts
+++ b/src/models/entities/user-publickey.ts
@@ -23,4 +23,12 @@ export class UserPublickey {
length: 4096,
})
public keyPem: string;
+
+ constructor(data: Partial) {
+ if (data == null) return;
+
+ for (const [k, v] of Object.entries(data)) {
+ (this as any)[k] = v;
+ }
+ }
}
diff --git a/src/models/entities/user.ts b/src/models/entities/user.ts
index ebf07ff3ff..e40c32a76f 100644
--- a/src/models/entities/user.ts
+++ b/src/models/entities/user.ts
@@ -205,6 +205,14 @@ export class User {
comment: 'The native access token of the User. It will be null if the origin of the user is local.'
})
public token: string | null;
+
+ constructor(data: Partial) {
+ if (data == null) return;
+
+ for (const [k, v] of Object.entries(data)) {
+ (this as any)[k] = v;
+ }
+ }
}
export interface ILocalUser extends User {
diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts
index ac18b18996..d7f2c3d040 100644
--- a/src/models/repositories/user.ts
+++ b/src/models/repositories/user.ts
@@ -87,7 +87,6 @@ export class UserRepository extends Repository {
name: user.name,
username: user.username,
host: user.host,
- uri: user.uri,
avatarUrl: user.avatarUrl,
bannerUrl: user.bannerUrl,
avatarColor: user.avatarColor,
@@ -118,6 +117,7 @@ export class UserRepository extends Repository {
} : {}),
...(opts.detail ? {
+ url: profile.url,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
description: profile.description,
diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts
index b2edf39734..58aca48eb0 100644
--- a/src/remote/activitypub/models/person.ts
+++ b/src/remote/activitypub/models/person.ts
@@ -25,6 +25,7 @@ import { isDuplicateKeyValueError } from '../../../misc/is-duplicate-key-value-e
import { toPuny } from '../../../misc/convert-host';
import { UserProfile } from '../../../models/entities/user-profile';
import { validActor } from '../../../remote/activitypub/type';
+import { getConnection } from 'typeorm';
const logger = apLogger;
/**
@@ -136,27 +137,42 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise) as IRemoteUser;
+ // Start transaction
+ await getConnection().transaction(async transactionalEntityManager => {
+ user = await transactionalEntityManager.save(new User({
+ id: genId(),
+ avatarId: null,
+ bannerId: null,
+ createdAt: new Date(person.published) || new Date(),
+ lastFetchedAt: new Date(),
+ name: person.name,
+ isLocked: person.manuallyApprovesFollowers,
+ username: person.preferredUsername,
+ usernameLower: person.preferredUsername.toLowerCase(),
+ host,
+ inbox: person.inbox,
+ sharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined),
+ featured: person.featured,
+ uri: person.id,
+ tags,
+ isBot,
+ isCat: (person as any).isCat === true
+ })) as IRemoteUser;
+
+ await transactionalEntityManager.save(new UserProfile({
+ userId: user.id,
+ description: fromHtml(person.summary),
+ url: person.url,
+ fields,
+ userHost: host
+ }));
+
+ await transactionalEntityManager.save(new UserPublickey({
+ userId: user.id,
+ keyId: person.publicKey.id,
+ keyPem: person.publicKey.publicKeyPem
+ }));
+ });
} catch (e) {
// duplicate key error
if (isDuplicateKeyValueError(e)) {
@@ -167,19 +183,6 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise);
-
- await UserPublickeys.save({
- userId: user.id,
- keyId: person.publicKey.id,
- keyPem: person.publicKey.publicKeyPem
- } as UserPublickey);
-
// Register host
registerOrFetchInstanceDoc(host).then(i => {
Instances.increment({ id: i.id }, 'usersCount', 1);
diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts
index 5ed25fa411..ed4a533dec 100644
--- a/src/server/api/private/signup.ts
+++ b/src/server/api/private/signup.ts
@@ -12,6 +12,7 @@ import { User } from '../../../models/entities/user';
import { UserKeypair } from '../../../models/entities/user-keypair';
import { toPuny } from '../../../misc/convert-host';
import { UserProfile } from '../../../models/entities/user-profile';
+import { getConnection } from 'typeorm';
export default async (ctx: Koa.BaseContext) => {
const body = ctx.request.body as any;
@@ -99,28 +100,33 @@ export default async (ctx: Koa.BaseContext) => {
e ? j(e) : s([publicKey, privateKey])
));
- const account = await Users.save({
- id: genId(),
- createdAt: new Date(),
- username: username,
- usernameLower: username.toLowerCase(),
- host: toPuny(host),
- token: secret,
- isAdmin: config.autoAdmin && usersCount === 0,
- } as User);
+ let account: User;
- await UserKeypairs.save({
- publicKey: keyPair[0],
- privateKey: keyPair[1],
- userId: account.id
- } as UserKeypair);
+ // Start transaction
+ await getConnection().transaction(async transactionalEntityManager => {
+ account = await transactionalEntityManager.save(new User({
+ id: genId(),
+ createdAt: new Date(),
+ username: username,
+ usernameLower: username.toLowerCase(),
+ host: toPuny(host),
+ token: secret,
+ isAdmin: config.autoAdmin && usersCount === 0,
+ }));
- await UserProfiles.save({
- userId: account.id,
- autoAcceptFollowed: true,
- autoWatch: false,
- password: hash,
- } as Partial);
+ await transactionalEntityManager.save(new UserKeypair({
+ publicKey: keyPair[0],
+ privateKey: keyPair[1],
+ userId: account.id
+ }));
+
+ await transactionalEntityManager.save(new UserProfile({
+ userId: account.id,
+ autoAcceptFollowed: true,
+ autoWatch: false,
+ password: hash,
+ }));
+ });
usersChart.update(account, true);
diff --git a/src/server/web/index.ts b/src/server/web/index.ts
index de0d65cf33..d1a15e3929 100644
--- a/src/server/web/index.ts
+++ b/src/server/web/index.ts
@@ -16,7 +16,7 @@ import fetchMeta from '../../misc/fetch-meta';
import * as pkg from '../../../package.json';
import { genOpenapiSpec } from '../api/openapi/gen-spec';
import config from '../../config';
-import { Users, Notes, Emojis } from '../../models';
+import { Users, Notes, Emojis, UserProfiles } from '../../models';
import parseAcct from '../../misc/acct/parse';
import getNoteSummary from '../../misc/get-note-summary';
@@ -149,11 +149,14 @@ router.get('/@:user', async (ctx, next) => {
usernameLower: username.toLowerCase(),
host
});
+ const profile = await UserProfiles.findOne({
+ userId: user.id
+ });
if (user != null) {
const meta = await fetchMeta();
await ctx.render('user', {
- user,
+ user, profile,
instanceName: meta.name || 'Misskey'
});
ctx.set('Cache-Control', 'public, max-age=180');
diff --git a/src/server/web/views/user.pug b/src/server/web/views/user.pug
index 3f32933f52..bff98ba80f 100644
--- a/src/server/web/views/user.pug
+++ b/src/server/web/views/user.pug
@@ -9,12 +9,12 @@ block title
= `${title} | ${instanceName}`
block desc
- meta(name='description' content= user.description)
+ meta(name='description' content= profile.description)
block og
meta(property='og:type' content='blog')
meta(property='og:title' content= title)
- meta(property='og:description' content= user.description)
+ meta(property='og:description' content= profile.description)
meta(property='og:url' content= url)
meta(property='og:image' content= img)
@@ -24,12 +24,12 @@ block meta
meta(name='twitter:card' content='summary')
- if user.twitter
- meta(name='twitter:creator' content=`@${user.twitter.screenName}`)
+ if profile.twitter
+ meta(name='twitter:creator' content=`@${profile.twitter.screenName}`)
if !user.host
- link(rel='alternate' href=`${config.url}/users/${user._id}` type='application/activity+json')
+ link(rel='alternate' href=`${config.url}/users/${user.id}` type='application/activity+json')
if user.uri
link(rel='alternate' href=user.uri type='application/activity+json')
- if user.url
- link(rel='alternate' href=user.url type='text/html')
+ if profile.url
+ link(rel='alternate' href=profile.url type='text/html')