Vulcan/packages/vulcan-posts/lib/schema.js
2017-08-20 17:01:57 +09:00

278 lines
5.3 KiB
JavaScript

import Users from 'meteor/vulcan:users';
import Posts from './collection.js';
import { Utils } from 'meteor/vulcan:core';
/**
* @summary Posts config namespace
* @type {Object}
*/
const formGroups = {
admin: {
name: "admin",
order: 2
}
};
/**
* @summary Posts schema
* @type {Object}
*/
const schema = {
/**
ID
*/
_id: {
type: String,
optional: true,
viewableBy: ['guests'],
},
/**
Timetstamp of post creation
*/
createdAt: {
type: Date,
optional: true,
viewableBy: ['admins'],
onInsert: (document, currentUser) => {
return new Date();
}
},
/**
Timestamp of post first appearing on the site (i.e. being approved)
*/
postedAt: {
type: Date,
optional: true,
viewableBy: ['guests'],
insertableBy: ['admins'],
editableBy: ['admins'],
control: "datetime",
group: formGroups.admin
},
/**
URL
*/
url: {
type: String,
optional: true,
max: 500,
viewableBy: ['guests'],
insertableBy: ['members'],
editableBy: ['members'],
control: "url",
order: 10,
searchable: true
},
/**
Title
*/
title: {
type: String,
optional: false,
max: 500,
viewableBy: ['guests'],
insertableBy: ['members'],
editableBy: ['members'],
control: "text",
order: 20,
searchable: true
},
/**
Slug
*/
slug: {
type: String,
optional: true,
viewableBy: ['guests'],
},
/**
Post body (markdown)
*/
body: {
type: String,
optional: true,
max: 3000,
viewableBy: ['guests'],
insertableBy: ['members'],
editableBy: ['members'],
control: "textarea",
order: 30
},
/**
HTML version of the post body
*/
htmlBody: {
type: String,
optional: true,
viewableBy: ['guests'],
},
/**
Post Excerpt
*/
excerpt: {
type: String,
optional: true,
viewableBy: ['guests'],
searchable: true
},
/**
Count of how many times the post's page was viewed
*/
viewCount: {
type: Number,
optional: true,
viewableBy: ['admins'],
defaultValue: 0
},
/**
Timestamp of the last comment
*/
lastCommentedAt: {
type: Date,
optional: true,
viewableBy: ['guests'],
},
/**
Count of how many times the post's link was clicked
*/
clickCount: {
type: Number,
optional: true,
viewableBy: ['admins'],
defaultValue: 0
},
/**
The post's status. One of pending (`1`), approved (`2`), or deleted (`3`)
*/
status: {
type: Number,
optional: true,
viewableBy: ['guests'],
insertableBy: ['admins'],
editableBy: ['admins'],
control: "select",
onInsert: document => {
if (document.userId && !document.status) {
const user = Users.findOne(document.userId);
return Posts.getDefaultStatus(user);
}
},
form: {
noselect: true,
options: () => Posts.statuses,
group: 'admin'
},
group: formGroups.admin
},
/**
Whether a post is scheduled in the future or not
*/
isFuture: {
type: Boolean,
optional: true,
viewableBy: ['guests'],
},
/**
Whether the post is sticky (pinned to the top of posts lists)
*/
sticky: {
type: Boolean,
optional: true,
defaultValue: false,
viewableBy: ['guests'],
insertableBy: ['admins'],
editableBy: ['admins'],
control: "checkbox",
group: formGroups.admin
},
/**
Whether the post is inactive. Inactive posts see their score recalculated less often
*/
inactive: {
type: Boolean,
optional: true,
defaultValue: false
},
/**
Save info for later spam checking on a post. We will use this for the akismet package
*/
userIP: {
type: String,
optional: true,
viewableBy: ['admins'],
},
userAgent: {
type: String,
optional: true,
viewableBy: ['admins'],
},
referrer: {
type: String,
optional: true,
viewableBy: ['admins'],
},
/**
The post author's name
*/
author: {
type: String,
optional: true,
viewableBy: ['guests'],
onEdit: (modifier, document, currentUser) => {
// if userId is changing, change the author name too
if (modifier.$set && modifier.$set.userId) {
return Users.getDisplayNameById(modifier.$set.userId)
}
}
},
/**
The post author's `_id`.
*/
userId: {
type: String,
optional: true,
control: "select",
viewableBy: ['guests'],
insertableBy: ['members'],
hidden: true,
resolveAs: {
fieldName: 'user',
type: 'User',
resolver: async (post, args, context) => {
if (!post.userId) return null;
const user = await context.Users.loader.load(post.userId);
return context.Users.restrictViewableFields(context.currentUser, context.Users, user);
},
addOriginalField: true
},
},
// GraphQL-only fields
pageUrl: {
type: String,
optional: true,
resolveAs: {
fieldName: 'pageUrl',
type: 'String',
resolver: (post, args, context) => {
return Posts.getPageUrl(post, true);
},
}
},
linkUrl: {
type: String,
optional: true,
resolveAs: {
fieldName: 'linkUrl',
type: 'String',
resolver: (post, args, context) => {
return post.url ? Utils.getOutgoingUrl(post.url) : Posts.getPageUrl(post, true);
},
}
}
};
export default schema;