js/models/Post.js
import Data from '~/models/Data';
import User from '~/models/User';
import CanonicalPostURL from '~/models/Request/CanonicalPostURL';
export const MIN_TITLE_LENGTH = Data.shared.envValueForKey('POST_TITLE_MIN');
export const MAX_TITLE_LENGTH = Data.shared.envValueForKey('POST_TITLE_MAX');
export const MIN_BODY_LENGTH = Data.shared.envValueForKey('POST_BODY_MIN');
export const MAX_BODY_LENGTH = Data.shared.envValueForKey('POST_BODY_MAX');
export const POST_JSON_KEY = 'post';
export const NOT_A_POST = Symbol('Post.NotAPost');
/**
* Describes a code-golf post
*/
export default class Post {
/**
* Pass all parameters as **object**
* @param {number} postId - Id of post.
* @param {string} title - Post title
* @param {?string} body - Post body
* @param {boolean} [isDeleted=false] - True if is deleted
* @param {string} slug - Slug of post
* @param {?User} owner - Owner of post
* @param {?Date} dateCreated - Date created
*/
constructor({ postId, title, body = null, slug = null, isDeleted = false, owner = null, dateCreated }) {
this._id = postId;
this._title = title;
this._body = body;
this._owner = owner;
this._slug = slug;
this._deleted = isDeleted;
this._dateCreated = dateCreated;
}
/** @type {Date} */
get dateCreated() { return this._dateCreated; }
/** @type {boolean} */
get isDeleted() { return this._deleted; }
/** @type {boolean} */
set isDeleted(isDeleted) { this._deleted = isDeleted; }
/** @type {number} */
get id() { return this._id; }
/** @type {string} */
get title() { return this._title; }
/** @type {?string} */
get body() { return this._body; }
/** @type {?User} */
get owner() { return this._owner; }
/**
* General endpoint for this type of model
* @type {string}
*/
get endpoint() { return 'post' }
/**
* Converts from JSON
* @return {Post}
*/
static fromJSON(json) {
return new Post({
postId: json.id,
title: json.title,
body: json.body || null,
slug: json.slug || null,
owner: User.fromJSON(json.owner),
isDeleted: json.deleted
})
}
/**
* Returns the canonical URL
* @return {string}
*/
async getURL() {
let slug;
if (!this._slug) {
slug = await new CanonicalPostURL(this).run();
} else {
slug = this._slug;
}
return `${Data.shared.envValueForKey('HOST')}/post/${this.id}/${slug}`;
}
/**
* Gets a post URL sync. May not be canonical
* @return {string}
*/
getURLSync() {
return `${Data.shared.envValueForKey('HOST')}/post/${this.id}/${this._slug || ''}`
}
/**
* Gets the description for this post
*/
async getDescription() {
const currentDescription = document.querySelector('meta[name=description]')?.content;
if (Post.current?.id === this.id && currentDescription) {
// If the current post is loaded get the link description from HTML
return currentDescription;
} else {
return new CanonicalPostDescription(this);
}
}
/**
* Generates a "QAPost" schema
*/
async getSchema() {
const canonicalURL = await this.getURL();
const description = await this.getDescription();
return ({
"@context": "http://schema.org",
"@type": "QAPage",
author: await this.owner.getSchema(),
breadcrumb: {
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"item": {
"@id": `${Data.shared.envValueForKey('HOST')}/posts`,
"name": "Posts"
}
}
]
},
description: description,
identifier: canonicalURL,
mainContentOfPage: {
cssSelector: ".body"
},
name: this.title,
text: description,
url: canonicalURL,
});
}
/**
* Unwraps from serach Index JSON object
* @param {Object} JSON Search index JSON
* @return {?User} Created object
*/
static fromIndexJSON(json) {
return new Post({
postId: json.id,
title: json.title,
body: json.body,
slug: json.slug,
owner: User.fromIndexJSON(json.author),
dateCreated: new Date(json.date_created)
});
}
/**
* Converts to json
* @return {Object} json object
*/
toJSON() {
return {
type: 'post',
body: this.body || undefined,
id: this.id,
deleted: this.isDeleted
};
}
static _currentPost = null;
/**
* The current post
* @type {Post}
*/
static get current() {
if (Post._currentPost === NOT_A_POST) return null;
if (Post._currentPost !== null) return Post._currentPost;
let postJson = Data.shared.encodedJSONForKey(POST_JSON_KEY);
if (postJson === null) {
Post._currentPost = NOT_A_POST;
return null;
}
return Post.fromJSON(postJson);
}
}