Move profile-related functions into PhotoProfile

The previous Profile type was renamed to PassportProfile, as it is only used for profile-information from Passport plugins.
All functions relating to profile-parsing are now encapsulated in the PhotoProfile class (naming still debatable).

Signed-off-by: David Mehren <dmehren1@gmail.com>
This commit is contained in:
David Mehren 2020-06-04 21:25:42 +02:00
parent 4552085ae0
commit 4e7c82dc3b
No known key found for this signature in database
GPG key ID: 6017AF117F9756CB
5 changed files with 84 additions and 92 deletions

View file

@ -1,4 +1,5 @@
import { Note } from './note'
import scrypt from 'scrypt-kdf'
import { UUIDV4 } from 'sequelize'
import {
BeforeCreate,
BeforeUpdate,
@ -12,10 +13,9 @@ import {
Table,
Unique
} from 'sequelize-typescript'
import scrypt from 'scrypt-kdf'
import { generateAvatarURL } from '../letter-avatars'
import { logger } from '../logger'
import { UUIDV4 } from 'sequelize'
import { Note } from './note'
// core
@ -31,8 +31,7 @@ export enum ProviderEnum {
saml = 'saml',
}
// ToDo Fix this 'any' mess
export type Profile = {
export type PassportProfile = {
id: string;
username: string;
displayName: string;
@ -43,49 +42,41 @@ export type Profile = {
photos: { value: string }[];
}
export type PhotoProfile = {
name: string;
photo: string;
biggerphoto: string;
export class PhotoProfile {
name: string
photo: string
biggerphoto: string
static fromUser (user: User): PhotoProfile | null {
if (!user) return null
if (user.profile) return PhotoProfile.fromJSON(user.profile)
if (user.email) return PhotoProfile.fromEmail(user.email)
return null
}
@Table
export class User extends Model<User> {
@PrimaryKey
@Default(UUIDV4)
@Column(DataType.UUID)
id: string
private static fromJSON (jsonProfile: string): PhotoProfile | null {
try {
const parsedProfile: PassportProfile = JSON.parse(jsonProfile)
return {
name: parsedProfile.displayName || parsedProfile.username,
photo: PhotoProfile.generatePhotoURL(parsedProfile, false),
biggerphoto: PhotoProfile.generatePhotoURL(parsedProfile, true)
}
} catch (err) {
logger.error(err)
return null
}
}
@Unique
@Column(DataType.STRING)
profileid: string
private static fromEmail (email: string): PhotoProfile {
return {
name: email.substring(0, email.lastIndexOf('@')),
photo: generateAvatarURL('', email, false),
biggerphoto: generateAvatarURL('', email, true)
}
}
@Column(DataType.TEXT)
profile: string
@Column(DataType.TEXT)
history: string
@Column(DataType.TEXT)
accessToken: string
@Column(DataType.TEXT)
refreshToken: string
@Column(DataType.UUID)
deleteToken: string
@IsEmail
@Column(DataType.TEXT)
email: string
@Column(DataType.TEXT)
password: string
@HasMany(() => Note, { foreignKey: 'lastchangeuserId', constraints: false })
@HasMany(() => Note, { foreignKey: 'ownerId', constraints: false })
static parsePhotoByProfile (profile: Profile, bigger: boolean): string {
private static generatePhotoURL (profile: PassportProfile, bigger: boolean): string {
let photo: string
switch (profile.provider) {
case ProviderEnum.facebook:
@ -147,14 +138,43 @@ export class User extends Model<User> {
}
return photo
}
}
static parseProfileByEmail (email: string): PhotoProfile {
return {
name: email.substring(0, email.lastIndexOf('@')),
photo: generateAvatarURL('', email, false),
biggerphoto: generateAvatarURL('', email, true)
}
}
@Table
export class User extends Model<User> {
@PrimaryKey
@Default(UUIDV4)
@Column(DataType.UUID)
id: string
@Unique
@Column(DataType.STRING)
profileid: string
@Column(DataType.TEXT)
profile: string
@Column(DataType.TEXT)
history: string
@Column(DataType.TEXT)
accessToken: string
@Column(DataType.TEXT)
refreshToken: string
@Column(DataType.UUID)
deleteToken: string
@IsEmail
@Column(DataType.TEXT)
email: string
@Column(DataType.TEXT)
password: string
@HasMany(() => Note, { foreignKey: 'lastchangeuserId', constraints: false })
@HasMany(() => Note, { foreignKey: 'ownerId', constraints: false })
@BeforeUpdate
@BeforeCreate
@ -173,37 +193,7 @@ export class User extends Model<User> {
})
}
static getProfile (user: User): PhotoProfile | null {
if (!user) {
return null
}
if (user.profile) {
return user.parseProfile(user.profile)
} else {
if (user.email) {
return User.parseProfileByEmail(user.email)
} else {
return null
}
}
}
verifyPassword (attempt: string): Promise<boolean> {
return scrypt.verify(Buffer.from(this.password, 'hex'), attempt)
}
parseProfile (profile: string): PhotoProfile | null {
try {
const parsedProfile: Profile = JSON.parse(profile)
return {
name: parsedProfile.displayName || parsedProfile.username,
photo: User.parsePhotoByProfile(parsedProfile, false),
biggerphoto: User.parsePhotoByProfile(parsedProfile, true)
}
} catch (err) {
logger.error(err)
return null
}
}
}

View file

@ -11,7 +11,7 @@ import { History } from './history'
import { logger } from './logger'
import { Author, Note, Revision, User } from './models'
import { NoteAuthorship } from './models/note'
import { PhotoProfile } from './models/user'
import { PhotoProfile, PassportProfile } from './models/user'
import { EditorSocketIOServer } from './ot/editor-socketio-server'
import { mapToObject } from './utils'
@ -169,7 +169,7 @@ function updateNote (note: NoteSession, callback: (err, note) => void): void {
}
}).then(function (user) {
if (!user) return callback(null, null)
note.lastchangeuserprofile = User.getProfile(user)
note.lastchangeuserprofile = PhotoProfile.fromUser(user)
return finishUpdateNote(note, _note, callback)
}).catch(function (err) {
logger.error(err)
@ -626,10 +626,10 @@ function startConnection (socket: SocketWithNoteId): void {
return failConnection(404, 'note not found', socket)
}
const owner = note.ownerId
const ownerprofile = note.owner ? User.getProfile(note.owner) : null
const ownerprofile = note.owner ? PhotoProfile.fromUser(note.owner) : null
const lastchangeuser = note.lastchangeuserId
const lastchangeuserprofile = note.lastchangeuser ? User.getProfile(note.lastchangeuser) : null
const lastchangeuserprofile = note.lastchangeuser ? PhotoProfile.fromUser(note.lastchangeuser) : null
const body = note.content
const createtime = note.createdAt
@ -638,7 +638,7 @@ function startConnection (socket: SocketWithNoteId): void {
const authors = new Map<string, UserSession>()
for (const author of note.authors) {
const profile = User.getProfile(author.user)
const profile = PhotoProfile.fromUser(author.user)
if (profile) {
authors.set(author.userId, {
userid: author.userId,
@ -767,7 +767,7 @@ setInterval(function () {
function updateUserData (socket: Socket, user): void {
// retrieve user data from passport
if (socket.request.user && socket.request.user.logged_in) {
const profile = User.getProfile(socket.request.user)
const profile = PhotoProfile.fromUser(socket.request.user)
user.photo = profile?.photo
user.name = profile?.name
user.userid = socket.request.user.id

View file

@ -1,6 +1,6 @@
import { InternalOAuthError, Strategy as OAuth2Strategy } from 'passport-oauth2'
import { config } from '../../../config'
import { Profile, ProviderEnum } from '../../../models/user'
import { PassportProfile, ProviderEnum } from '../../../models/user'
function extractProfileAttribute (data, path: string): string {
// can handle stuff like `attrs[0].name`
@ -13,7 +13,7 @@ function extractProfileAttribute (data, path: string): string {
return data
}
function parseProfile (data): Partial<Profile> {
function parseProfile (data): Partial<PassportProfile> {
const username = extractProfileAttribute(data, config.oauth2.userProfileUsernameAttr)
const displayName = extractProfileAttribute(data, config.oauth2.userProfileDisplayNameAttr)
const email = extractProfileAttribute(data, config.oauth2.userProfileEmailAttr)

View file

@ -6,6 +6,7 @@ import { config } from '../../config'
import { errors } from '../../errors'
import { logger } from '../../logger'
import { Note, User } from '../../models'
import { PassportProfile, PhotoProfile } from '../../models/user'
export function newNote (req, res: Response, body: string | null): void {
let owner = null
@ -96,9 +97,9 @@ export function getPublishData (req: Request, res: Response, note, callback: (da
theme: meta.slideOptions && isRevealTheme(meta.slideOptions.theme),
meta: JSON.stringify(extracted.meta),
owner: note.owner ? note.owner.id : null,
ownerprofile: note.owner ? User.getProfile(note.owner) : null,
ownerprofile: note.owner ? PhotoProfile.fromUser(note.owner) : null,
lastchangeuser: note.lastchangeuser ? note.lastchangeuser.id : null,
lastchangeuserprofile: note.lastchangeuser ? User.getProfile(note.lastchangeuser) : null,
lastchangeuserprofile: note.lastchangeuser ? PhotoProfile.fromUser(note.lastchangeuser) : null,
robots: meta.robots || false, // default allow robots
GA: meta.GA,
disqus: meta.disqus,

View file

@ -6,6 +6,7 @@ import { Note, User } from '../models'
import { logger } from '../logger'
import { generateAvatar } from '../letter-avatars'
import { config } from '../config'
import { PassportProfile, PhotoProfile } from '../models/user'
const UserRouter = Router()
@ -21,7 +22,7 @@ UserRouter.get('/me', function (req: Request, res: Response) {
}
}).then(function (user) {
if (!user) { return errors.errorNotFound(res) }
const profile = User.getProfile(user)
const profile = PhotoProfile.fromUser(user)
if (profile == null) {
return errors.errorInternalError(res)
}