Show user fields (#3590)
This commit is contained in:
parent
1d1a373ca8
commit
638d81b66e
7 changed files with 132 additions and 1 deletions
|
@ -26,6 +26,14 @@
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
|
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="fields" v-if="user.fields">
|
||||||
|
<dl class="field" v-for="(field, i) in user.fields" :key="i">
|
||||||
|
<dt class="name">{{ field.name }}</dt>
|
||||||
|
<dd class="value">
|
||||||
|
<misskey-flavored-markdown :text="field.value" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
<div class="counts">
|
<div class="counts">
|
||||||
<div>
|
<div>
|
||||||
<b>{{ user.notesCount | number }}</b>
|
<b>{{ user.notesCount | number }}</b>
|
||||||
|
@ -416,6 +424,31 @@ export default Vue.extend({
|
||||||
border-right solid 16px transparent
|
border-right solid 16px transparent
|
||||||
border-bottom solid 16px var(--face)
|
border-bottom solid 16px var(--face)
|
||||||
|
|
||||||
|
> .fields
|
||||||
|
margin-top 8px
|
||||||
|
|
||||||
|
> .field
|
||||||
|
display flex
|
||||||
|
padding 0
|
||||||
|
margin 0
|
||||||
|
|
||||||
|
> .name
|
||||||
|
padding 4px
|
||||||
|
margin 4px
|
||||||
|
width 30%
|
||||||
|
overflow hidden
|
||||||
|
white-space nowrap
|
||||||
|
text-overflow ellipsis
|
||||||
|
font-weight bold
|
||||||
|
|
||||||
|
> .value
|
||||||
|
padding 4px
|
||||||
|
margin 4px
|
||||||
|
width 70%
|
||||||
|
overflow hidden
|
||||||
|
white-space nowrap
|
||||||
|
text-overflow ellipsis
|
||||||
|
|
||||||
> .counts
|
> .counts
|
||||||
display grid
|
display grid
|
||||||
grid-template-columns 1fr 1fr 1fr
|
grid-template-columns 1fr 1fr 1fr
|
||||||
|
|
|
@ -18,6 +18,14 @@
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
|
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="fields" v-if="user.fields">
|
||||||
|
<dl class="field" v-for="(field, i) in user.fields" :key="i">
|
||||||
|
<dt class="name">{{ field.name }}</dt>
|
||||||
|
<dd class="value">
|
||||||
|
<misskey-flavored-markdown :text="field.value" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span class="location" v-if="user.host === null && user.profile.location"><fa icon="map-marker"/> {{ user.profile.location }}</span>
|
<span class="location" v-if="user.host === null && user.profile.location"><fa icon="map-marker"/> {{ user.profile.location }}</span>
|
||||||
<span class="birthday" v-if="user.host === null && user.profile.birthday"><fa icon="birthday-cake"/> {{ user.profile.birthday.replace('-', $t('year')).replace('-', $t('month')) + $t('day') }} ({{ $t('years-old', { age }) }})</span>
|
<span class="birthday" v-if="user.host === null && user.profile.birthday"><fa icon="birthday-cake"/> {{ user.profile.birthday.replace('-', $t('year')).replace('-', $t('month')) + $t('day') }} ({{ $t('years-old', { age }) }})</span>
|
||||||
|
@ -174,6 +182,33 @@ export default Vue.extend({
|
||||||
padding 16px 16px 16px 154px
|
padding 16px 16px 16px 154px
|
||||||
color var(--text)
|
color var(--text)
|
||||||
|
|
||||||
|
> .fields
|
||||||
|
margin-top 16px
|
||||||
|
|
||||||
|
> .field
|
||||||
|
display flex
|
||||||
|
padding 0
|
||||||
|
margin 0
|
||||||
|
|
||||||
|
> .name
|
||||||
|
border-right solid 1px var(--faceDivider)
|
||||||
|
padding 4px
|
||||||
|
margin 4px
|
||||||
|
width 30%
|
||||||
|
overflow hidden
|
||||||
|
white-space nowrap
|
||||||
|
text-overflow ellipsis
|
||||||
|
font-weight bold
|
||||||
|
text-align center
|
||||||
|
|
||||||
|
> .value
|
||||||
|
padding 4px
|
||||||
|
margin 4px
|
||||||
|
width 70%
|
||||||
|
overflow hidden
|
||||||
|
white-space nowrap
|
||||||
|
text-overflow ellipsis
|
||||||
|
|
||||||
> .info
|
> .info
|
||||||
margin-top 16px
|
margin-top 16px
|
||||||
padding-top 16px
|
padding-top 16px
|
||||||
|
|
|
@ -24,6 +24,14 @@
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
|
<misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="fields" v-if="user.fields">
|
||||||
|
<dl class="field" v-for="(field, i) in user.fields" :key="i">
|
||||||
|
<dt class="name">{{ field.name }}</dt>
|
||||||
|
<dd class="value">
|
||||||
|
<misskey-flavored-markdown :text="field.value" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<p class="location" v-if="user.host === null && user.profile.location">
|
<p class="location" v-if="user.host === null && user.profile.location">
|
||||||
<fa icon="map-marker"/>{{ user.profile.location }}
|
<fa icon="map-marker"/>{{ user.profile.location }}
|
||||||
|
@ -301,6 +309,33 @@ main
|
||||||
margin 8px 0
|
margin 8px 0
|
||||||
color var(--mobileUserPageDescription)
|
color var(--mobileUserPageDescription)
|
||||||
|
|
||||||
|
> .fields
|
||||||
|
margin 8px 0
|
||||||
|
|
||||||
|
> .field
|
||||||
|
display flex
|
||||||
|
padding 0
|
||||||
|
margin 0
|
||||||
|
|
||||||
|
> .name
|
||||||
|
padding 4px
|
||||||
|
margin 4px
|
||||||
|
width 30%
|
||||||
|
overflow hidden
|
||||||
|
white-space nowrap
|
||||||
|
text-overflow ellipsis
|
||||||
|
font-weight bold
|
||||||
|
color var(--mobileUserPageStatusHighlight)
|
||||||
|
|
||||||
|
> .value
|
||||||
|
padding 4px
|
||||||
|
margin 4px
|
||||||
|
width 70%
|
||||||
|
overflow hidden
|
||||||
|
white-space nowrap
|
||||||
|
text-overflow ellipsis
|
||||||
|
color var(--mobileUserPageStatusHighlight)
|
||||||
|
|
||||||
> .info
|
> .info
|
||||||
margin 8px 0
|
margin 8px 0
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ export default function(html: string): string {
|
||||||
if ((rel && rel.value.match('tag') !== null) || !href || href.value == txt) {
|
if ((rel && rel.value.match('tag') !== null) || !href || href.value == txt) {
|
||||||
text += txt;
|
text += txt;
|
||||||
// メンション
|
// メンション
|
||||||
} else if (txt.startsWith('@')) {
|
} else if (txt.startsWith('@') && !rel || !rel.value.match(/^me /)) {
|
||||||
const part = txt.split('@');
|
const part = txt.split('@');
|
||||||
|
|
||||||
if (part.length == 2) {
|
if (part.length == 2) {
|
||||||
|
|
|
@ -109,6 +109,10 @@ export interface ILocalUser extends IUserBase {
|
||||||
birthday: string; // 'YYYY-MM-DD'
|
birthday: string; // 'YYYY-MM-DD'
|
||||||
tags: string[];
|
tags: string[];
|
||||||
};
|
};
|
||||||
|
fields?: {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
isCat: boolean;
|
isCat: boolean;
|
||||||
isAdmin?: boolean;
|
isAdmin?: boolean;
|
||||||
isModerator?: boolean;
|
isModerator?: boolean;
|
||||||
|
|
|
@ -17,6 +17,7 @@ import registerInstance from '../../../services/register-instance';
|
||||||
import Instance from '../../../models/instance';
|
import Instance from '../../../models/instance';
|
||||||
import getDriveFileUrl from '../../../misc/get-drive-file-url';
|
import getDriveFileUrl from '../../../misc/get-drive-file-url';
|
||||||
import { IEmoji } from '../../../models/emoji';
|
import { IEmoji } from '../../../models/emoji';
|
||||||
|
import { ITag } from './tag';
|
||||||
|
|
||||||
const log = debug('misskey:activitypub');
|
const log = debug('misskey:activitypub');
|
||||||
|
|
||||||
|
@ -135,6 +136,10 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
|
||||||
|
|
||||||
const host = toUnicode(new URL(object.id).hostname.toLowerCase());
|
const host = toUnicode(new URL(object.id).hostname.toLowerCase());
|
||||||
|
|
||||||
|
const fields = await extractFields(person.attachment).catch(e => {
|
||||||
|
console.log(`cat not extract fields: ${e}`);
|
||||||
|
});
|
||||||
|
|
||||||
const isBot = object.type == 'Service';
|
const isBot = object.type == 'Service';
|
||||||
|
|
||||||
// Create user
|
// Create user
|
||||||
|
@ -164,6 +169,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU
|
||||||
endpoints: person.endpoints,
|
endpoints: person.endpoints,
|
||||||
uri: person.id,
|
uri: person.id,
|
||||||
url: person.url,
|
url: person.url,
|
||||||
|
fields,
|
||||||
isBot: isBot,
|
isBot: isBot,
|
||||||
isCat: (person as any).isCat === true
|
isCat: (person as any).isCat === true
|
||||||
}) as IRemoteUser;
|
}) as IRemoteUser;
|
||||||
|
@ -325,6 +331,10 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
|
||||||
|
|
||||||
const emojiNames = emojis.map(emoji => emoji.name);
|
const emojiNames = emojis.map(emoji => emoji.name);
|
||||||
|
|
||||||
|
const fields = await extractFields(person.attachment).catch(e => {
|
||||||
|
console.log(`cat not extract fields: ${e}`);
|
||||||
|
});
|
||||||
|
|
||||||
// Update user
|
// Update user
|
||||||
await User.update({ _id: exist._id }, {
|
await User.update({ _id: exist._id }, {
|
||||||
$set: {
|
$set: {
|
||||||
|
@ -346,6 +356,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje
|
||||||
name: person.name,
|
name: person.name,
|
||||||
url: person.url,
|
url: person.url,
|
||||||
endpoints: person.endpoints,
|
endpoints: person.endpoints,
|
||||||
|
fields,
|
||||||
isBot: object.type == 'Service',
|
isBot: object.type == 'Service',
|
||||||
isCat: (person as any).isCat === true,
|
isCat: (person as any).isCat === true,
|
||||||
isLocked: person.manuallyApprovesFollowers,
|
isLocked: person.manuallyApprovesFollowers,
|
||||||
|
@ -382,6 +393,18 @@ export async function resolvePerson(uri: string, verifier?: string, resolver?: R
|
||||||
return await createPerson(uri, resolver);
|
return await createPerson(uri, resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function extractFields(attachments: ITag[]) {
|
||||||
|
if (!attachments) return [];
|
||||||
|
|
||||||
|
return attachments.filter(a => a.type === 'PropertyValue' && a.name && a.value)
|
||||||
|
.map(a => {
|
||||||
|
return {
|
||||||
|
name: a.name,
|
||||||
|
value: htmlToMFM(a.value)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function updateFeatured(userId: mongo.ObjectID) {
|
export async function updateFeatured(userId: mongo.ObjectID) {
|
||||||
const user = await User.findOne({ _id: userId });
|
const user = await User.findOne({ _id: userId });
|
||||||
if (!isRemoteUser(user)) return;
|
if (!isRemoteUser(user)) return;
|
||||||
|
|
|
@ -7,6 +7,7 @@ export type ITag = {
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
value?: string;
|
||||||
updated?: Date;
|
updated?: Date;
|
||||||
icon?: IIcon;
|
icon?: IIcon;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue