Retro style default profile, constant cleanup, some DRY, etc.
This commit is contained in:
parent
2a75d55b42
commit
3bdce81bdb
|
@ -1,5 +1,11 @@
|
||||||
const { localActorId } = require('./util');
|
const { localActorId } = require('./util');
|
||||||
const { WellKnownActivityTypes } = require('./const');
|
const {
|
||||||
|
ActivityStreamMediaType,
|
||||||
|
WellKnownActivityTypes,
|
||||||
|
WellKnownActivity,
|
||||||
|
WellKnownRecipientFields,
|
||||||
|
HttpSignatureSignHeaders,
|
||||||
|
} = require('./const');
|
||||||
const ActivityPubObject = require('./object');
|
const ActivityPubObject = require('./object');
|
||||||
const { Errors } = require('../enig_error');
|
const { Errors } = require('../enig_error');
|
||||||
const UserProps = require('../user_property');
|
const UserProps = require('../user_property');
|
||||||
|
@ -26,7 +32,7 @@ module.exports = class Activity extends ActivityPubObject {
|
||||||
static makeFollow(webServer, localActor, remoteActor) {
|
static makeFollow(webServer, localActor, remoteActor) {
|
||||||
return new Activity({
|
return new Activity({
|
||||||
id: Activity.activityObjectId(webServer),
|
id: Activity.activityObjectId(webServer),
|
||||||
type: 'Follow',
|
type: WellKnownActivity.Follow,
|
||||||
actor: localActor,
|
actor: localActor,
|
||||||
object: remoteActor.id,
|
object: remoteActor.id,
|
||||||
});
|
});
|
||||||
|
@ -36,7 +42,7 @@ module.exports = class Activity extends ActivityPubObject {
|
||||||
static makeAccept(webServer, localActor, followRequest) {
|
static makeAccept(webServer, localActor, followRequest) {
|
||||||
return new Activity({
|
return new Activity({
|
||||||
id: Activity.activityObjectId(webServer),
|
id: Activity.activityObjectId(webServer),
|
||||||
type: 'Accept',
|
type: WellKnownActivity.Accept,
|
||||||
actor: localActor,
|
actor: localActor,
|
||||||
object: followRequest, // previous request Activity
|
object: followRequest, // previous request Activity
|
||||||
});
|
});
|
||||||
|
@ -45,7 +51,7 @@ module.exports = class Activity extends ActivityPubObject {
|
||||||
static makeCreate(webServer, actor, obj) {
|
static makeCreate(webServer, actor, obj) {
|
||||||
return new Activity({
|
return new Activity({
|
||||||
id: Activity.activityObjectId(webServer),
|
id: Activity.activityObjectId(webServer),
|
||||||
type: 'Create',
|
type: WellKnownActivity.Create,
|
||||||
actor,
|
actor,
|
||||||
object: obj,
|
object: obj,
|
||||||
});
|
});
|
||||||
|
@ -55,7 +61,7 @@ module.exports = class Activity extends ActivityPubObject {
|
||||||
const deleted = getISOTimestampString();
|
const deleted = getISOTimestampString();
|
||||||
return new Activity({
|
return new Activity({
|
||||||
id: obj.id,
|
id: obj.id,
|
||||||
type: 'Tombstone',
|
type: WellKnownActivity.Tombstone,
|
||||||
deleted,
|
deleted,
|
||||||
published: deleted,
|
published: deleted,
|
||||||
updated: deleted,
|
updated: deleted,
|
||||||
|
@ -74,14 +80,13 @@ module.exports = class Activity extends ActivityPubObject {
|
||||||
|
|
||||||
const reqOpts = {
|
const reqOpts = {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/activity+json',
|
'Content-Type': ActivityStreamMediaType,
|
||||||
},
|
},
|
||||||
sign: {
|
sign: {
|
||||||
// :TODO: Make a helper for this
|
|
||||||
key: privateKey,
|
key: privateKey,
|
||||||
keyId: localActorId(webServer, fromUser) + '#main-key',
|
keyId: localActorId(webServer, fromUser) + '#main-key',
|
||||||
authorizationHeaderName: 'Signature',
|
authorizationHeaderName: 'Signature',
|
||||||
headers: ['(request-target)', 'host', 'date', 'digest', 'content-type'],
|
headers: HttpSignatureSignHeaders,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,8 +97,7 @@ module.exports = class Activity extends ActivityPubObject {
|
||||||
recipientIds() {
|
recipientIds() {
|
||||||
const ids = [];
|
const ids = [];
|
||||||
|
|
||||||
// :TODO: bto, bcc?
|
WellKnownRecipientFields.forEach(field => {
|
||||||
['to', 'cc', 'audience'].forEach(field => {
|
|
||||||
let v = this[field];
|
let v = this[field];
|
||||||
if (v) {
|
if (v) {
|
||||||
if (!Array.isArray(v)) {
|
if (!Array.isArray(v)) {
|
||||||
|
@ -103,7 +107,7 @@ module.exports = class Activity extends ActivityPubObject {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return ids;
|
return Array.from(new Set(ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
static activityObjectId(webServer) {
|
static activityObjectId(webServer) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ const { queryWebFinger } = require('../webfinger');
|
||||||
const EnigAssert = require('../enigma_assert');
|
const EnigAssert = require('../enigma_assert');
|
||||||
const ActivityPubSettings = require('./settings');
|
const ActivityPubSettings = require('./settings');
|
||||||
const ActivityPubObject = require('./object');
|
const ActivityPubObject = require('./object');
|
||||||
|
const { ActivityStreamMediaType } = require('./const');
|
||||||
const apDb = require('../database').dbs.activitypub;
|
const apDb = require('../database').dbs.activitypub;
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
|
@ -96,6 +97,12 @@ module.exports = class Actor extends ActivityPubObject {
|
||||||
'@context': [
|
'@context': [
|
||||||
ActivityStreamsContext,
|
ActivityStreamsContext,
|
||||||
'https://w3id.org/security/v1', // :TODO: add support
|
'https://w3id.org/security/v1', // :TODO: add support
|
||||||
|
{
|
||||||
|
bbsPublicStats: {
|
||||||
|
'@id': 'bbs:bbsPublicStats',
|
||||||
|
'@type': '@id',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
id: userActorId,
|
id: userActorId,
|
||||||
type: 'Person',
|
type: 'Person',
|
||||||
|
@ -122,6 +129,25 @@ module.exports = class Actor extends ActivityPubObject {
|
||||||
// value: 'Mateo@21:1/121',
|
// value: 'Mateo@21:1/121',
|
||||||
// },
|
// },
|
||||||
// ],
|
// ],
|
||||||
|
bbsPublicStats: {
|
||||||
|
affiliations: user.getProperty(UserProps.Affiliations) || '',
|
||||||
|
lastLogin: user.getProperty(UserProps.LastLoginTs),
|
||||||
|
loginCount: user.getPropertyAsNumber(UserProps.LoginCount),
|
||||||
|
joined: user.getProperty(UserProps.AccountCreated),
|
||||||
|
postCount: user.getPropertyAsNumber(UserProps.MessagePostCount),
|
||||||
|
doorCount: user.getPropertyAsNumber(UserProps.DoorRunTotalCount),
|
||||||
|
doorMinute: user.getPropertyAsNumber(UserProps.DoorRunTotalMinutes),
|
||||||
|
achievementCount: user.getPropertyAsNumber(
|
||||||
|
UserProps.AchievementTotalCount
|
||||||
|
),
|
||||||
|
achievementPoints: user.getPropertyAsNumber(
|
||||||
|
UserProps.AchievementTotalPoints
|
||||||
|
),
|
||||||
|
uploadCount: user.getPropertyAsNumber(UserProps.FileUlTotalCount),
|
||||||
|
downloadCount: user.getPropertyAsNumber(UserProps.FileDlTotalCount),
|
||||||
|
uploadBytes: user.getPropertyAsNumber(UserProps.FileUlTotalBytes),
|
||||||
|
downloadBytes: user.getPropertyAsNumber(UserProps.FileDlTotalBytes),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
addImage(obj, 'icon');
|
addImage(obj, 'icon');
|
||||||
|
@ -190,7 +216,7 @@ module.exports = class Actor extends ActivityPubObject {
|
||||||
|
|
||||||
static _fromRemoteQuery(id, cb) {
|
static _fromRemoteQuery(id, cb) {
|
||||||
const headers = {
|
const headers = {
|
||||||
Accept: 'application/activity+json',
|
Accept: ActivityStreamMediaType,
|
||||||
};
|
};
|
||||||
|
|
||||||
getJson(id, { headers }, (err, actor) => {
|
getJson(id, { headers }, (err, actor) => {
|
||||||
|
@ -268,7 +294,7 @@ module.exports = class Actor extends ActivityPubObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
const activityLink = links.find(l => {
|
const activityLink = links.find(l => {
|
||||||
return l.type === 'application/activity+json' && l.href?.length > 0;
|
return l.type === ActivityStreamMediaType && l.href?.length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!activityLink) {
|
if (!activityLink) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
exports.ActivityStreamsContext = 'https://www.w3.org/ns/activitystreams';
|
exports.ActivityStreamsContext = 'https://www.w3.org/ns/activitystreams';
|
||||||
exports.PublicCollectionId = 'https://www.w3.org/ns/activitystreams#Public';
|
exports.PublicCollectionId = 'https://www.w3.org/ns/activitystreams#Public';
|
||||||
|
exports.ActivityStreamMediaType = 'application/activity+json';
|
||||||
|
|
||||||
const WellKnownActivity = {
|
const WellKnownActivity = {
|
||||||
Create: 'Create',
|
Create: 'Create',
|
||||||
|
@ -13,8 +14,20 @@ const WellKnownActivity = {
|
||||||
Like: 'Like',
|
Like: 'Like',
|
||||||
Announce: 'Announce',
|
Announce: 'Announce',
|
||||||
Undo: 'Undo',
|
Undo: 'Undo',
|
||||||
|
Tombstone: 'Tombstone',
|
||||||
};
|
};
|
||||||
exports.WellKnownActivity = WellKnownActivity;
|
exports.WellKnownActivity = WellKnownActivity;
|
||||||
|
|
||||||
const WellKnownActivityTypes = Object.values(WellKnownActivity);
|
const WellKnownActivityTypes = Object.values(WellKnownActivity);
|
||||||
exports.WellKnownActivityTypes = WellKnownActivityTypes;
|
exports.WellKnownActivityTypes = WellKnownActivityTypes;
|
||||||
|
|
||||||
|
exports.WellKnownRecipientFields = ['audience', 'bcc', 'bto', 'cc', 'to'];
|
||||||
|
|
||||||
|
// Signatures utilized in HTTP signature generation
|
||||||
|
exports.HttpSignatureSignHeaders = [
|
||||||
|
'(request-target)',
|
||||||
|
'host',
|
||||||
|
'date',
|
||||||
|
'digest',
|
||||||
|
'content-type',
|
||||||
|
];
|
||||||
|
|
|
@ -14,6 +14,7 @@ const paths = require('path');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const { striptags } = require('striptags');
|
const { striptags } = require('striptags');
|
||||||
const { encode, decode } = require('html-entities');
|
const { encode, decode } = require('html-entities');
|
||||||
|
const { isString } = require('lodash');
|
||||||
|
|
||||||
exports.ActivityStreamsContext = 'https://www.w3.org/ns/activitystreams';
|
exports.ActivityStreamsContext = 'https://www.w3.org/ns/activitystreams';
|
||||||
exports.isValidLink = isValidLink;
|
exports.isValidLink = isValidLink;
|
||||||
|
@ -32,9 +33,9 @@ exports.userNameFromSubject = userNameFromSubject;
|
||||||
// profiles and 'self' requests without the
|
// profiles and 'self' requests without the
|
||||||
// Accept: application/activity+json headers present
|
// Accept: application/activity+json headers present
|
||||||
exports.DefaultProfileTemplate = `
|
exports.DefaultProfileTemplate = `
|
||||||
User information for: %USERNAME%
|
User information for: %PREFERRED_USERNAME%
|
||||||
|
|
||||||
Real Name: %REAL_NAME%
|
Name: %NAME%
|
||||||
Login Count: %LOGIN_COUNT%
|
Login Count: %LOGIN_COUNT%
|
||||||
Affiliations: %AFFILIATIONS%
|
Affiliations: %AFFILIATIONS%
|
||||||
Achievement Points: %ACHIEVEMENT_POINTS%
|
Achievement Points: %ACHIEVEMENT_POINTS%
|
||||||
|
@ -102,8 +103,10 @@ function userFromActorId(actorId, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserProfileTemplatedBody(
|
function getUserProfileTemplatedBody(
|
||||||
|
webServer,
|
||||||
templateFile,
|
templateFile,
|
||||||
user,
|
user,
|
||||||
|
userAsActor,
|
||||||
defaultTemplate,
|
defaultTemplate,
|
||||||
defaultContentType,
|
defaultContentType,
|
||||||
cb
|
cb
|
||||||
|
@ -130,36 +133,53 @@ function getUserProfileTemplatedBody(
|
||||||
return callback(null, template, contentType);
|
return callback(null, template, contentType);
|
||||||
},
|
},
|
||||||
(template, contentType, callback) => {
|
(template, contentType, callback) => {
|
||||||
const up = (p, na = 'N/A') => {
|
const val = v => {
|
||||||
return user.getProperty(p) || na;
|
if (isString(v)) {
|
||||||
|
return v ? encode(v) : '';
|
||||||
|
} else {
|
||||||
|
return v ? v : 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let birthDate = up(UserProps.Birthdate);
|
let birthDate = val(user.getProperty(UserProps.Birthdate));
|
||||||
if (moment.isDate(birthDate)) {
|
if (moment.isDate(birthDate)) {
|
||||||
birthDate = moment(birthDate);
|
birthDate = moment(birthDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
const varMap = {
|
const varMap = {
|
||||||
USERNAME: user.username,
|
ACTOR_OBJ: JSON.stringify(userAsActor),
|
||||||
REAL_NAME: user.getSanitizedName('real'),
|
SUBJECT: `@${user.username}@${webServer.getDomain()}`,
|
||||||
SEX: up(UserProps.Sex),
|
INBOX: userAsActor.inbox,
|
||||||
|
SHARED_INBOX: userAsActor.endpoints.sharedInbox,
|
||||||
|
OUTBOX: userAsActor.outbox,
|
||||||
|
FOLLOWERS: userAsActor.followers,
|
||||||
|
FOLLOWING: userAsActor.following,
|
||||||
|
USER_ICON: userAsActor.icon.url,
|
||||||
|
USER_IMAGE: userAsActor.image.url,
|
||||||
|
PREFERRED_USERNAME: userAsActor.preferredUsername,
|
||||||
|
NAME: userAsActor.name,
|
||||||
|
SEX: user.getProperty(UserProps.Sex),
|
||||||
BIRTHDATE: birthDate,
|
BIRTHDATE: birthDate,
|
||||||
AGE: user.getAge(),
|
AGE: user.getAge(),
|
||||||
LOCATION: up(UserProps.Location),
|
LOCATION: user.getProperty(UserProps.Location),
|
||||||
AFFILIATIONS: up(UserProps.Affiliations),
|
AFFILIATIONS: user.getProperty(UserProps.Affiliations),
|
||||||
EMAIL: up(UserProps.EmailAddress),
|
EMAIL: user.getProperty(UserProps.EmailAddress),
|
||||||
WEB_ADDRESS: up(UserProps.WebAddress),
|
WEB_ADDRESS: user.getProperty(UserProps.WebAddress),
|
||||||
ACCOUNT_CREATED: moment(user.getProperty(UserProps.AccountCreated)),
|
ACCOUNT_CREATED: moment(user.getProperty(UserProps.AccountCreated)),
|
||||||
LAST_LOGIN: moment(user.getProperty(UserProps.LastLoginTs)),
|
LAST_LOGIN: moment(user.getProperty(UserProps.LastLoginTs)),
|
||||||
LOGIN_COUNT: up(UserProps.LoginCount),
|
LOGIN_COUNT: user.getPropertyAsNumber(UserProps.LoginCount),
|
||||||
ACHIEVEMENT_COUNT: up(UserProps.AchievementTotalCount, '0'),
|
ACHIEVEMENT_COUNT: user.getPropertyAsNumber(
|
||||||
ACHIEVEMENT_POINTS: up(UserProps.AchievementTotalPoints, '0'),
|
UserProps.AchievementTotalCount
|
||||||
|
),
|
||||||
|
ACHIEVEMENT_POINTS: user.getProperty(
|
||||||
|
UserProps.AchievementTotalPoints
|
||||||
|
),
|
||||||
BOARDNAME: Config().general.boardName,
|
BOARDNAME: Config().general.boardName,
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = template;
|
let body = template;
|
||||||
_.each(varMap, (val, varName) => {
|
_.each(varMap, (v, varName) => {
|
||||||
body = body.replace(new RegExp(`%${varName}%`, 'g'), val);
|
body = body.replace(new RegExp(`%${varName}%`, 'g'), val(v));
|
||||||
});
|
});
|
||||||
|
|
||||||
return callback(null, body, contentType);
|
return callback(null, body, contentType);
|
||||||
|
|
|
@ -324,6 +324,11 @@ exports.getModule = class WebServerModule extends ServerModule {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
created(resp, body = '', headers = { 'Content-Type:': 'text/html' }) {
|
||||||
|
resp.writeHead(201, 'Created', body ? headers : null);
|
||||||
|
return resp.end(body);
|
||||||
|
}
|
||||||
|
|
||||||
accepted(resp, body = '', headers = { 'Content-Type:': 'text/html' }) {
|
accepted(resp, body = '', headers = { 'Content-Type:': 'text/html' }) {
|
||||||
resp.writeHead(202, 'Accepted', body ? headers : null);
|
resp.writeHead(202, 'Accepted', body ? headers : null);
|
||||||
return resp.end(body);
|
return resp.end(body);
|
||||||
|
|
|
@ -6,6 +6,7 @@ const {
|
||||||
makeUserUrl,
|
makeUserUrl,
|
||||||
localActorId,
|
localActorId,
|
||||||
} = require('../../../activitypub/util');
|
} = require('../../../activitypub/util');
|
||||||
|
const { ActivityStreamMediaType } = require('../../../activitypub/const');
|
||||||
const Config = require('../../../config').get;
|
const Config = require('../../../config').get;
|
||||||
const Activity = require('../../../activitypub/activity');
|
const Activity = require('../../../activitypub/activity');
|
||||||
const ActivityPubSettings = require('../../../activitypub/settings');
|
const ActivityPubSettings = require('../../../activitypub/settings');
|
||||||
|
@ -31,8 +32,6 @@ exports.moduleInfo = {
|
||||||
packageName: 'codes.l33t.enigma.web.handler.activitypub',
|
packageName: 'codes.l33t.enigma.web.handler.activitypub',
|
||||||
};
|
};
|
||||||
|
|
||||||
const ActivityJsonMime = 'application/activity+json';
|
|
||||||
|
|
||||||
exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
@ -149,7 +148,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
// Additionally, serve activity JSON if the proper 'Accept' header was sent
|
// Additionally, serve activity JSON if the proper 'Accept' header was sent
|
||||||
const accept = req.headers['accept'].split(',').map(v => v.trim()) || ['*/*'];
|
const accept = req.headers['accept'].split(',').map(v => v.trim()) || ['*/*'];
|
||||||
const headerValues = [
|
const headerValues = [
|
||||||
ActivityJsonMime,
|
ActivityStreamMediaType,
|
||||||
'application/ld+json',
|
'application/ld+json',
|
||||||
'application/json',
|
'application/json',
|
||||||
];
|
];
|
||||||
|
@ -166,11 +165,17 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
return this.webServer.resourceNotFound(resp);
|
return this.webServer.resourceNotFound(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendActor) {
|
Actor.fromLocalUser(localUser, this.webServer, (err, localActor) => {
|
||||||
return this._selfAsActorHandler(localUser, req, resp);
|
if (err) {
|
||||||
} else {
|
return this.webServer.internalServerError(resp, err);
|
||||||
return this._standardSelfHandler(localUser, req, resp);
|
}
|
||||||
}
|
|
||||||
|
if (sendActor) {
|
||||||
|
return this._selfAsActorHandler(localUser, localActor, req, resp);
|
||||||
|
} else {
|
||||||
|
return this._standardSelfHandler(localUser, localActor, req, resp);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,7 +346,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
return this.webServer.internalServerError(resp, err);
|
return this.webServer.internalServerError(resp, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.webServer.accepted(resp);
|
return this.webServer.created(resp);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -409,7 +414,7 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
|
|
||||||
const body = JSON.stringify(collection);
|
const body = JSON.stringify(collection);
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type': ActivityJsonMime,
|
'Content-Type': ActivityStreamMediaType,
|
||||||
'Content-Length': body.length,
|
'Content-Length': body.length,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -700,30 +705,24 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
console.log(resp);
|
console.log(resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
_selfAsActorHandler(user, req, resp) {
|
_selfAsActorHandler(localUser, localActor, req, resp) {
|
||||||
this.log.trace(
|
this.log.trace(
|
||||||
{ username: user.username },
|
{ username: localUser.username },
|
||||||
`Serving ActivityPub Actor for "${user.username}"`
|
`Serving ActivityPub Actor for "${localUser.username}"`
|
||||||
);
|
);
|
||||||
|
|
||||||
Actor.fromLocalUser(user, this.webServer, (err, actor) => {
|
const body = JSON.stringify(localActor);
|
||||||
if (err) {
|
|
||||||
return this.webServer.internalServerError(resp, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = JSON.stringify(actor);
|
const headers = {
|
||||||
|
'Content-Type': ActivityStreamMediaType,
|
||||||
|
'Content-Length': body.length,
|
||||||
|
};
|
||||||
|
|
||||||
const headers = {
|
resp.writeHead(200, headers);
|
||||||
'Content-Type': ActivityJsonMime,
|
return resp.end(body);
|
||||||
'Content-Length': body.length,
|
|
||||||
};
|
|
||||||
|
|
||||||
resp.writeHead(200, headers);
|
|
||||||
return resp.end(body);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_standardSelfHandler(user, req, resp) {
|
_standardSelfHandler(localUser, localActor, req, resp) {
|
||||||
let templateFile = _.get(
|
let templateFile = _.get(
|
||||||
Config(),
|
Config(),
|
||||||
'contentServers.web.handlers.activityPub.selfTemplate'
|
'contentServers.web.handlers.activityPub.selfTemplate'
|
||||||
|
@ -734,8 +733,10 @@ exports.getModule = class ActivityPubWebHandler extends WebHandlerModule {
|
||||||
|
|
||||||
// we'll fall back to the same default profile info as the WebFinger profile
|
// we'll fall back to the same default profile info as the WebFinger profile
|
||||||
getUserProfileTemplatedBody(
|
getUserProfileTemplatedBody(
|
||||||
|
this.webServer,
|
||||||
templateFile,
|
templateFile,
|
||||||
user,
|
localUser,
|
||||||
|
localActor,
|
||||||
DefaultProfileTemplate,
|
DefaultProfileTemplate,
|
||||||
'text/plain',
|
'text/plain',
|
||||||
(err, body, contentType) => {
|
(err, body, contentType) => {
|
||||||
|
|
|
@ -15,6 +15,7 @@ const ActivityPubSettings = require('../../../activitypub/settings');
|
||||||
|
|
||||||
// deps
|
// deps
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const Actor = require('../../../activitypub/actor');
|
||||||
|
|
||||||
exports.moduleInfo = {
|
exports.moduleInfo = {
|
||||||
name: 'WebFinger',
|
name: 'WebFinger',
|
||||||
|
@ -104,25 +105,33 @@ exports.getModule = class WebFingerWebHandler extends WebHandlerModule {
|
||||||
templateFile = this.webServer.resolveTemplatePath(templateFile);
|
templateFile = this.webServer.resolveTemplatePath(templateFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserProfileTemplatedBody(
|
Actor.fromLocalUser(localUser, this.webServer, (err, localActor) => {
|
||||||
templateFile,
|
if (err) {
|
||||||
localUser,
|
return this.webServer.internalServerError(resp, err);
|
||||||
DefaultProfileTemplate,
|
|
||||||
'text/plain',
|
|
||||||
(err, body, contentType) => {
|
|
||||||
if (err) {
|
|
||||||
return this.webServer.resourceNotFound(resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const headers = {
|
|
||||||
'Content-Type': contentType,
|
|
||||||
'Content-Length': body.length,
|
|
||||||
};
|
|
||||||
|
|
||||||
resp.writeHead(200, headers);
|
|
||||||
return resp.end(body);
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
getUserProfileTemplatedBody(
|
||||||
|
this.webServer,
|
||||||
|
templateFile,
|
||||||
|
localUser,
|
||||||
|
localActor,
|
||||||
|
DefaultProfileTemplate,
|
||||||
|
'text/plain',
|
||||||
|
(err, body, contentType) => {
|
||||||
|
if (err) {
|
||||||
|
return this.webServer.resourceNotFound(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': contentType,
|
||||||
|
'Content-Length': body.length,
|
||||||
|
};
|
||||||
|
|
||||||
|
resp.writeHead(200, headers);
|
||||||
|
return resp.end(body);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,118 @@
|
||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html class="no-js" lang="en">
|
<html class="no-js" lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>%USERNAME%</title>
|
<title>%NAME%</title>
|
||||||
<meta name="description" content="Profile of %USERNAME% of %BOARDNAME%">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
</head>
|
<meta name="description" content="Profile of %PREFERRED_USERNAME% of %BOARDNAME%">
|
||||||
<body>
|
</head>
|
||||||
<h1>%USERNAME% of %BOARDNAME%:</h1>
|
<style>
|
||||||
<p>
|
body {
|
||||||
<b>Real Name</b>: %REAL_NAME%<br>
|
margin: 0 auto;
|
||||||
<b>Location</b>: %LOCATION%<br>
|
padding: 0;
|
||||||
<b>Login Count</b> %LOGIN_COUNT%<br>
|
background: #000;
|
||||||
<b>Affils</b>: %AFFILIATIONS%<br>
|
}
|
||||||
<b>Account Since</b>: %ACCOUNT_CREATED%<br>
|
|
||||||
</p>
|
.left {
|
||||||
</body>
|
left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
right: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#gradient {
|
||||||
|
background: #999955;
|
||||||
|
background-image: linear-gradient(#aa5500 20%, #aa0000 20%, #aa0000 40%, #00aa00 40%, #00aa00 60%, #00aaaa 60%, #00aaaa 80%, #aa00aa 80%);
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-top: 100px;
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#gradient:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
background: #555555;
|
||||||
|
left: 50%;
|
||||||
|
margin-top: -67.5px;
|
||||||
|
margin-left: -270px;
|
||||||
|
padding-left: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 520px;
|
||||||
|
height: 275px;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#card {
|
||||||
|
position: absolute;
|
||||||
|
width: 450px;
|
||||||
|
height: 225px;
|
||||||
|
padding: 25px;
|
||||||
|
padding-top: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
top: 67.5px;
|
||||||
|
margin-left: -250px;
|
||||||
|
background: #aaaaaa;
|
||||||
|
box-shadow: -20px 0 35px -25px black, 20px 0 35px -25px black;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#card img {
|
||||||
|
width: 150px;
|
||||||
|
float: left;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-right: 20px;
|
||||||
|
-webkit-filter: sepia(1);
|
||||||
|
-moz-filter: sepia(1);
|
||||||
|
filter: sepia(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#card h2 {
|
||||||
|
font-family: courier;
|
||||||
|
color: #ff55ff;
|
||||||
|
background: #aa00aa;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 15pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#card p {
|
||||||
|
font-family: courier;
|
||||||
|
color: #000000;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#card span {
|
||||||
|
font-family: courier;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<div id="gradient"></div>
|
||||||
|
<div id="card">
|
||||||
|
<img src="%USER_ICON%" />
|
||||||
|
<h2>%NAME%</h2>
|
||||||
|
<p>
|
||||||
|
<b>Name</b>: %NAME% <br>
|
||||||
|
<b>Location</b>: %LOCATION% <br>
|
||||||
|
<b>Login Count</b>: %LOGIN_COUNT% <br>
|
||||||
|
<b>Last Login <b>: %LAST_LOGIN% <br>
|
||||||
|
<b>Affils</b>: %AFFILIATIONS% <br>
|
||||||
|
<b>Account Since</b>: %ACCOUNT_CREATED% <br>
|
||||||
|
</p>
|
||||||
|
<span class="left bottom">%SUBJECT%</span>
|
||||||
|
<span class="right bottom">%BOARDNAME%!</span>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue