Home Reference Source

js/models/Answer.js

import ErrorManager from '~/helpers/ErrorManager';
import Language from '~/models/Language';
import Data, { EnvKey } from '~/models/Data';
import User from '~/models/User';
import Post from '~/models/Post';

export const INVALID_JSON = Symbol('User.Error.InvalidJSON');

/**
 * An answer to a challenge
 * @implements {JSONConvertable}
 */
export default class Answer {
    /**
     * Creates an answer from an answer config object
     * @param {Object} answer
     * @param {number} answer.id
     * @param {?string} answer.code
     * @param {?string} answer.encoding
     * @param {boolean} [answer.deleted=false]
     * @param {?string} answer.commentary
     * @param {?number} answer.length
     * @param {?Language} answer.language
     * @param {User} answer.user
     * @param {?Post} answer.post Parent post
     * @param {?Date} answer.dateCreated
     * @param {?Date} answer.dateModified
     */
    constructor({ id, code, encoding, deleted = false, length, language, commentary, user, post, dateCreated, dateModified }) {
        this._id = id;
        this._code = code;
        this._encoding = encoding;
        this._deleted = deleted;
        this._commentary = commentary;
        this._length = length;
        this._language = language;
        this._user = user;
        this._post = post;
        this._dateCreated = dateCreated;
        this._dateModified = dateModified;
    }

    /**
     * Clones and returns a new copy of the answer. This is not deep
     * @return {Answer} a copy
     */
    clone() {
        return new Answer({
            id: this._id,
            code: this._code,
            encoding: this._encoding,
            commentary: this._commentary,
            length: this._length,
            language: this._language,
            user: this._user
        });
    }

    /**
     * @type {?Date}
     */
    get dateCreated() { return this._dateCreated; }

    /**
     * @type {?Date}
     */
    get dateModified() { return this._dateModified; }

    /**
     * @type {?Post}
     */
    get post() { return this._post; }

    /**
     * @type {number}
     */
    get id() { return this._id }

    /**
     * General endpoint for this type of model
     * @type {string}
     */
    get endpoint() { return 'answer' }

    /**
     * Language of ans
     * @type {?Language}
     */
    get language() { return this._language; }

    /**
     * Returns length of answer
     * @type {?number}
     */
    get length() {
        return this._length || (this._code ? this._code.length : null)
    }

    /**
     * Returns the code
     * @type {string}
     */
    get code() { return this._code; }

    /**
     * Sets the code
     * @type {string}
     */
    set code(code) {
        // TODO: support encodings
        this._length = [...code].length;
        this._code = code;
    }

    /**
     * Returns owner of the answer
     * @type {User}
     */
    get user() { return this._user; }

    /**
     * Gets if deleted
     */
    get isDeleted() { return this._deleted; }

    /**
     * Gets if deleted
     */
    set isDeleted(isDeleted) { this._deleted = isDeleted; }

    /**
     * URL of answer
     * @return {string}
     */
    get url() {
        return `${Data.shared.envValueForKey(EnvKey.host)}/answer/${this.id}`;
    }

    /**
     * Converts to json
     * @return {Object} json object
     */
    toJSON() {
        return {
            type: 'answer',
            id: this.id,
            owner: this.user.toJSON(),
            code: this.code,
            deleted: this.isDeleted,
            byte_len: this.length,
            lang: this.language
        };
    }

    /**
     * Unwraps from serach Index JSON object
     * @param {Object} JSON Search index JSON
     * @return {?User} Created object
     */
    static fromIndexJSON(json) {
        return new Answer({
            id: json.id,
            code: json.code,
            deleted: false,
            length: json.byte_count,
            language: Language.fromJSON(json.language),
            user: User.fromIndexJSON(json.author),
            dateCreated: new Date(json.date_created),
            dateModified: new Date(json.last_modified),
            post: new Post({ postId: json.post.id, title: json.post.name, slug: json.post.slug })
        });
    }

    /**
     * Unwraps from an API JSON object.
     * @param {Object} json User JSON object.
     * @return {?Answer} object if succesful, `null` if unauthorized.
     * @throws {TypeError} if invalid JSON object
     */
    static fromJSON(json) {
        // Unwrap all json parameters
        const {
            id,
            code = null,
            encoding = "utf8",
            commentary = "",
            lang: language,
            deleted = false,
            byte_len: length,
            owner
        } = json;

        if (!owner) {
            ErrorManager.raise(`Incomplete Answer JSON`, INVALID_JSON);
        }

        return new Answer({
            id,
            code,
            encoding,
            commentary,
            deleted,
            language: Language.fromJSON(language),
            length,
            user: User.fromJSON(owner)
        });
    }
}