Initial commit
This commit is contained in:
commit
92e96b9107
85 changed files with 24969 additions and 0 deletions
111
app/server/models/Article.ts
Normal file
111
app/server/models/Article.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
import { Schema, model, Document, Types } from 'mongoose'
|
||||
|
||||
export interface IRevision {
|
||||
content: string
|
||||
author: Types.ObjectId
|
||||
message: string
|
||||
createdAt: Date
|
||||
}
|
||||
|
||||
export interface IComment {
|
||||
author: Types.ObjectId
|
||||
content: string
|
||||
parentComment?: Types.ObjectId
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
resolved: boolean
|
||||
}
|
||||
|
||||
export interface IArticle extends Document {
|
||||
slug: string
|
||||
title: string
|
||||
description: string
|
||||
content: string // Current content in markdown
|
||||
category: string
|
||||
tags: string[]
|
||||
|
||||
// Access control
|
||||
accessLevel: 'public' | 'member' | 'cohort' | 'admin'
|
||||
cohorts?: string[] // Specific cohorts if accessLevel is 'cohort'
|
||||
|
||||
// Metadata
|
||||
author: Types.ObjectId
|
||||
contributors: Types.ObjectId[]
|
||||
views: number
|
||||
likes: number
|
||||
|
||||
// Editing
|
||||
status: 'draft' | 'published' | 'archived'
|
||||
lockedBy?: Types.ObjectId // If someone is currently editing
|
||||
lockedAt?: Date
|
||||
|
||||
// History
|
||||
revisions: IRevision[]
|
||||
comments: IComment[]
|
||||
|
||||
// Timestamps
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
publishedAt?: Date
|
||||
}
|
||||
|
||||
const revisionSchema = new Schema<IRevision>({
|
||||
content: { type: String, required: true },
|
||||
author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
|
||||
message: { type: String, required: true },
|
||||
createdAt: { type: Date, default: Date.now }
|
||||
})
|
||||
|
||||
const commentSchema = new Schema<IComment>({
|
||||
author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
|
||||
content: { type: String, required: true },
|
||||
parentComment: { type: Schema.Types.ObjectId, ref: 'Comment' },
|
||||
resolved: { type: Boolean, default: false }
|
||||
}, {
|
||||
timestamps: true
|
||||
})
|
||||
|
||||
const articleSchema = new Schema<IArticle>({
|
||||
slug: { type: String, required: true, unique: true },
|
||||
title: { type: String, required: true },
|
||||
description: { type: String, required: true },
|
||||
content: { type: String, required: true },
|
||||
category: { type: String, required: true },
|
||||
tags: [{ type: String }],
|
||||
|
||||
accessLevel: {
|
||||
type: String,
|
||||
enum: ['public', 'member', 'cohort', 'admin'],
|
||||
default: 'member'
|
||||
},
|
||||
cohorts: [{ type: String }],
|
||||
|
||||
author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
|
||||
contributors: [{ type: Schema.Types.ObjectId, ref: 'User' }],
|
||||
views: { type: Number, default: 0 },
|
||||
likes: { type: Number, default: 0 },
|
||||
|
||||
status: {
|
||||
type: String,
|
||||
enum: ['draft', 'published', 'archived'],
|
||||
default: 'draft'
|
||||
},
|
||||
lockedBy: { type: Schema.Types.ObjectId, ref: 'User' },
|
||||
lockedAt: Date,
|
||||
|
||||
revisions: [revisionSchema],
|
||||
comments: [commentSchema],
|
||||
|
||||
publishedAt: Date
|
||||
}, {
|
||||
timestamps: true
|
||||
})
|
||||
|
||||
// Indexes for better query performance
|
||||
articleSchema.index({ slug: 1 })
|
||||
articleSchema.index({ accessLevel: 1, status: 1 })
|
||||
articleSchema.index({ tags: 1 })
|
||||
articleSchema.index({ category: 1 })
|
||||
articleSchema.index({ author: 1 })
|
||||
|
||||
export const Article = model<IArticle>('Article', articleSchema)
|
||||
47
app/server/models/User.ts
Normal file
47
app/server/models/User.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { Schema, model, Document } from 'mongoose'
|
||||
|
||||
export interface IUser extends Document {
|
||||
ghostguildId: string // ID from ghostguild-org
|
||||
email: string
|
||||
username: string
|
||||
displayName: string
|
||||
avatar?: string
|
||||
roles: string[] // 'admin', 'moderator', 'member', 'cohort-X'
|
||||
permissions: {
|
||||
canEdit: boolean
|
||||
canModerate: boolean
|
||||
canAdmin: boolean
|
||||
}
|
||||
contributions: {
|
||||
edits: number
|
||||
comments: number
|
||||
articles: number
|
||||
}
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
lastLogin: Date
|
||||
}
|
||||
|
||||
const userSchema = new Schema<IUser>({
|
||||
ghostguildId: { type: String, required: true, unique: true },
|
||||
email: { type: String, required: true, unique: true },
|
||||
username: { type: String, required: true, unique: true },
|
||||
displayName: { type: String, required: true },
|
||||
avatar: String,
|
||||
roles: [{ type: String }],
|
||||
permissions: {
|
||||
canEdit: { type: Boolean, default: false },
|
||||
canModerate: { type: Boolean, default: false },
|
||||
canAdmin: { type: Boolean, default: false }
|
||||
},
|
||||
contributions: {
|
||||
edits: { type: Number, default: 0 },
|
||||
comments: { type: Number, default: 0 },
|
||||
articles: { type: Number, default: 0 }
|
||||
},
|
||||
lastLogin: { type: Date, default: Date.now }
|
||||
}, {
|
||||
timestamps: true
|
||||
})
|
||||
|
||||
export const User = model<IUser>('User', userSchema)
|
||||
Loading…
Add table
Add a link
Reference in a new issue