Vulcan/packages/nova-posts/lib/schema.js

426 lines
9.3 KiB
JavaScript
Raw Normal View History

import Telescope from 'meteor/nova:lib';
2016-06-23 15:00:58 +09:00
import Posts from './collection.js';
import Users from 'meteor/nova:users';
import marked from 'marked';
2016-06-23 15:00:58 +09:00
/**
* @summary Posts config namespace
* @type {Object}
*/
Posts.config = {};
Posts.config.STATUS_PENDING = 1;
Posts.config.STATUS_APPROVED = 2;
Posts.config.STATUS_REJECTED = 3;
Posts.config.STATUS_SPAM = 4;
Posts.config.STATUS_DELETED = 5;
2016-07-19 15:13:16 +09:00
Posts.formGroups = {
2016-07-13 11:46:45 +09:00
admin: {
name: "admin",
order: 2
}
};
2016-06-23 15:00:58 +09:00
2016-07-21 09:40:05 +09:00
// check if user can create a new post
const canInsert = user => Users.canDo(user, "posts.new");
// check if user can edit a post
const canEdit = Users.canEdit;
// check if user can edit *all* posts
const canEditAll = user => Users.canDo(user, "posts.edit.all");
const alwaysPublic = user => true;
2016-06-23 15:00:58 +09:00
/**
* @summary Posts schema
* @type {SimpleSchema}
*/
Posts.schemaJSON = {
/**
ID
*/
_id: {
type: String,
optional: true,
2016-11-08 15:16:58 +09:00
publish: true,
viewableIf: alwaysPublic,
2016-06-23 15:00:58 +09:00
},
/**
Timetstamp of post creation
*/
createdAt: {
type: Date,
optional: true,
viewableIf: canEditAll,
publish: true, // publish so that admins can sort pending posts by createdAt
autoValue: (documentOrModifier) => {
if (documentOrModifier && !documentOrModifier.$set) return new Date() // if this is an insert, set createdAt to current timestamp
}
2016-06-23 15:00:58 +09:00
},
/**
Timestamp of post first appearing on the site (i.e. being approved)
*/
postedAt: {
type: Date,
optional: true,
viewableIf: alwaysPublic,
2016-07-21 09:40:05 +09:00
insertableIf: canEditAll,
editableIf: canEditAll,
2016-06-23 15:00:58 +09:00
publish: true,
control: "datetime",
2016-07-19 15:13:16 +09:00
group: Posts.formGroups.admin
2016-06-23 15:00:58 +09:00
},
/**
URL
*/
url: {
type: String,
optional: true,
max: 500,
viewableIf: alwaysPublic,
2016-07-21 09:40:05 +09:00
insertableIf: canInsert,
editableIf: canEdit,
2016-06-23 15:00:58 +09:00
control: "text",
publish: true,
order: 10
},
/**
Title
*/
title: {
type: String,
optional: false,
max: 500,
viewableIf: alwaysPublic,
2016-07-21 09:40:05 +09:00
insertableIf: canInsert,
editableIf: canEdit,
2016-06-23 15:00:58 +09:00
control: "text",
publish: true,
order: 20
},
/**
Slug
*/
slug: {
type: String,
optional: true,
viewableIf: alwaysPublic,
2016-06-23 15:00:58 +09:00
publish: true,
autoValue: (documentOrModifier) => {
// if title is changing, return new slug
const newTitle = documentOrModifier.title || documentOrModifier.$set && documentOrModifier.$set.title
if (newTitle) {
return Telescope.utils.slugify(newTitle)
}
}
2016-06-23 15:00:58 +09:00
},
/**
Post body (markdown)
*/
body: {
type: String,
optional: true,
max: 3000,
viewableIf: alwaysPublic,
2016-07-21 09:40:05 +09:00
insertableIf: canInsert,
editableIf: canEdit,
2016-06-23 15:00:58 +09:00
control: "textarea",
publish: true,
order: 30
},
/**
HTML version of the post body
*/
htmlBody: {
type: String,
optional: true,
publish: true,
viewableIf: alwaysPublic,
autoValue(documentOrModifier) {
const body = documentOrModifier.body || documentOrModifier.$set && documentOrModifier.$set.body;
if (body) {
return Telescope.utils.sanitize(marked(body))
} else if (documentOrModifier.$unset && documentOrModifier.$unset.body) {
return ''
}
}
2016-06-23 15:00:58 +09:00
},
/**
Post Excerpt
*/
excerpt: {
type: String,
optional: true,
max: 255, //should not be changed the 255 is max we should load for each post/item
publish: true,
viewableIf: alwaysPublic,
autoValue(documentOrModifier) {
const body = documentOrModifier.body || documentOrModifier.$set && documentOrModifier.$set.body;
if (body) {
return Telescope.utils.trimHTML(Telescope.utils.sanitize(marked(body)), 30);
} else if (documentOrModifier.$unset && documentOrModifier.$unset.body) {
return ''
}
}
2016-06-23 15:00:58 +09:00
},
/**
Count of how many times the post's page was viewed
*/
viewCount: {
type: Number,
optional: true,
publish: true,
viewableIf: alwaysPublic,
2016-06-23 15:00:58 +09:00
defaultValue: 0
},
/**
Timestamp of the last comment
*/
lastCommentedAt: {
type: Date,
optional: true,
publish: true,
viewableIf: alwaysPublic,
2016-06-23 15:00:58 +09:00
},
/**
Count of how many times the post's link was clicked
*/
clickCount: {
type: Number,
optional: true,
publish: true,
viewableIf: canEditAll,
2016-06-23 15:00:58 +09:00
defaultValue: 0
},
/**
The post's status. One of pending (`1`), approved (`2`), or deleted (`3`)
*/
status: {
type: Number,
optional: true,
viewableIf: alwaysPublic,
2016-07-21 09:40:05 +09:00
insertableIf: canEditAll,
editableIf: canEditAll,
2016-06-23 15:00:58 +09:00
control: "select",
publish: true,
autoValue(documentOrModifier) {
// provide a default value if this is an insert operation and status field is not set in the document
if (documentOrModifier && !documentOrModifier.$set && documentOrModifier.userId) {
const user = Users.findOne(documentOrModifier.userId);
2016-06-23 15:00:58 +09:00
return Posts.getDefaultStatus(user);
}
2016-06-23 15:00:58 +09:00
},
form: {
2016-06-23 15:00:58 +09:00
noselect: true,
options: Telescope.statuses,
2016-06-23 15:00:58 +09:00
group: 'admin'
},
2016-07-19 15:13:16 +09:00
group: Posts.formGroups.admin
2016-06-23 15:00:58 +09:00
},
/**
Whether a post is scheduled in the future or not
*/
isFuture: {
type: Boolean,
optional: true,
viewableIf: alwaysPublic,
publish: true
},
2016-06-23 15:00:58 +09:00
/**
Whether the post is sticky (pinned to the top of posts lists)
*/
sticky: {
type: Boolean,
optional: true,
defaultValue: false,
viewableIf: alwaysPublic,
2016-07-21 09:40:05 +09:00
insertableIf: canEditAll,
editableIf: canEditAll,
2016-06-23 15:00:58 +09:00
control: "checkbox",
publish: true,
2016-07-19 15:13:16 +09:00
group: Posts.formGroups.admin
2016-06-23 15:00:58 +09:00
},
/**
Whether the post is inactive. Inactive posts see their score recalculated less often
*/
inactive: {
type: Boolean,
optional: true,
publish: false,
defaultValue: false
},
/**
Save info for later spam checking on a post. We will use this for the akismet package
*/
userIP: {
type: String,
optional: true,
viewableIf: canEditAll,
2016-06-23 15:00:58 +09:00
publish: false
},
userAgent: {
type: String,
optional: true,
viewableIf: canEditAll,
2016-06-23 15:00:58 +09:00
publish: false
},
referrer: {
type: String,
optional: true,
viewableIf: canEditAll,
2016-06-23 15:00:58 +09:00
publish: false
},
/**
The post author's name
*/
author: {
type: String,
optional: true,
viewableIf: alwaysPublic,
2016-06-23 15:00:58 +09:00
publish: true,
autoValue: (documentOrModifier) => {
// if userId is changing, change the author name too
const userId = documentOrModifier.userId || documentOrModifier.$set && documentOrModifier.$set.userId
if (userId) return Users.getDisplayNameById(userId)
}
2016-06-23 15:00:58 +09:00
},
/**
The post author's `_id`.
*/
userId: {
type: String,
optional: true,
control: "select",
viewableIf: alwaysPublic,
insertableIf: canInsert,
control: "none",
resolveAs: 'user: User',
// publish: true,
2016-06-23 15:00:58 +09:00
// regEx: SimpleSchema.RegEx.Id,
2016-07-21 09:40:05 +09:00
// insertableIf: canEditAll,
// editableIf: canEditAll,
// form: {
// group: 'admin',
// options: function () {
// return Users.find().map(function (user) {
// return {
// value: user._id,
// label: Users.getDisplayName(user)
// };
// });
// }
// },
// join: {
// joinAs: "user",
// collection: () => Users
// }
2016-06-23 15:00:58 +09:00
}
};
if (typeof SimpleSchema !== "undefined") {
Posts.schema = new SimpleSchema(Posts.schemaJSON);
Posts.attachSchema(Posts.schema);
}
// Posts.graphQLSchema = `
// type Post {
// _id: String
// createdAt: String
// postedAt: String
// url: String
// title: String
// slug: String
// body: String
// htmlBody: String
// excerpt: String
// sticky: Boolean
// viewCount: Int
// lastCommentedAt: String
// clickCount: Int
// status: Int
// isFuture: Boolean
// user: User
// commentCount: Int
// commenters: [User]
// # comments: [Comment]
// categories: [Category]
// scheduledAt: String
// dummySlug: String
// isDummy: String
// upvotes: Int
// upvoters: [User]
// downvotes: Int
// downvoters: [User]
// baseScore: Int
// score: Float
// clickCount: Int
// viewCount: Int
// thumbnailUrl: String
// userIP: String
// userAgent: String
// referrer: String
// }
2016-11-04 14:38:31 +09:00
// input postsInput {
// postedAt: String
// url: String
// title: String
// slug: String
// body: String
// sticky: Boolean
// status: Int
// categories: [String]
// scheduledAt: String
// thumbnailUrl: String
// }
// input postsUnset {
// postedAt: Boolean
// url: Boolean
// title: Boolean
// slug: Boolean
// body: Boolean
// sticky: Boolean
// status: Boolean
// categories: Boolean
// scheduledAt: Boolean
// thumbnailUrl: Boolean
// }
// input Terms {
// view: String
// userId: String
// cat: String
// date: String
// after: String
// before: String
// enableCache: Boolean
// listId: String
// query: String # search query
// }
// `;
2016-11-07 17:45:17 +09:00
2016-11-08 15:12:23 +09:00
Telescope.graphQL.addCollection(Posts);
const termsSchema = `
input Terms {
view: String
userId: String
cat: String
date: String
after: String
before: String
enableCache: Boolean
listId: String
query: String # search query
}
`;
Telescope.graphQL.addSchema(termsSchema);
2016-11-03 21:39:09 +09:00
Telescope.graphQL.addToContext({ Posts });