@stackend/api
Version:
JS bindings to api.stackend.com
273 lines (230 loc) • 7.08 kB
text/typescript
import { getJson, post, XcapJsonResult, Thunk } from '../api';
import { ModerationStatus, ModerationStatusCode, ModerationStatusCodes } from '../api/ModerationStatus';
import { Order } from '../api/Order';
import ModerationVisibility from '../api/ModerationVisibility';
import { User } from '../user';
import { PaginatedCollection } from '../api/PaginatedCollection';
import XcapObject from '../api/XcapObject';
/**
* Result of a single content filter
*/
export interface ContentFilterResult {
/** Name of the content filter */
filterName: string;
/** Resulting moderation status */
modStatus: ModerationStatusCodes;
/** Optional values indicating why a filter modified the modStatus, for example SPOOF: 3 */
keyValues: { [key: string]: string | number };
/** Labels assigned, for example keywords when scanning text or images */
labels: Array<string>;
}
/**
* Result of content filtering
*/
export interface ContentFilterResults {
/** Over all resulting moderation status (most restrictive of all filters) */
modStatus: ModerationStatusCodes;
/** Results from individual content filtering plugins */
results: Array<ContentFilterResult>;
}
/**
* Get the most restrictive ModerationStatus status
* @param m1
* @param m2
* @returns {string}
*/
export function getMostRestrictiveModerationStatus(m1: ModerationStatus, m2: ModerationStatus): ModerationStatus {
if (m1 === ModerationStatus.NOT_PASSED || m2 === ModerationStatus.NOT_PASSED) {
return ModerationStatus.NOT_PASSED;
}
if (m1 === ModerationStatus.PRE || m2 === ModerationStatus.PRE) {
return ModerationStatus.PRE;
}
if (m1 === ModerationStatus.POST || m2 === ModerationStatus.POST) {
return ModerationStatus.POST;
}
if (m1 === ModerationStatus.NONE || m2 === ModerationStatus.NONE) {
return ModerationStatus.NONE;
}
return ModerationStatus.PASSED;
}
/**
* Get the most restrictive mod status
* @param m1
* @param m2
* @returns {number}
*/
export function getMostRestrictiveModStatus(m1: number, m2: number): ModerationStatusCodes {
if (m1 === 2 || m2 === 2) {
return 2;
}
if (m1 === 4 || m2 === 4) {
return 4;
}
if (m1 === 5 || m2 === 5) {
return 5;
}
if (m1 === 0 || m2 === 0) {
return 0;
}
if (m1 === 1 || m2 === 1) {
return 1;
}
return 0;
}
/**
* Combine all content filter results to a single result
* @param results
*/
export function combineContentFilterResults(results: Array<ContentFilterResult>): ContentFilterResult {
const r: ContentFilterResult = {
filterName: '',
modStatus: ModerationStatusCode[ModerationStatus.NONE] as ModerationStatusCodes,
keyValues: {},
labels: []
};
if (!results || results.length === 0) {
return r;
}
results.forEach(x => {
r.modStatus = getMostRestrictiveModStatus(x.modStatus, r.modStatus);
if (x.keyValues) {
Object.keys(x.keyValues).map(key => {
const v = x.keyValues[key];
const n = r.keyValues[key];
if (!n || parseInt(v + '') > parseInt(n + '')) {
r.keyValues[key] = v;
}
});
}
// TODO: Labels ignored
});
return r;
}
/**
* Check if a an object is visible
* @param object
* @returns {boolean}
*/
export function isVisible(object: XcapObject): boolean {
if (!object) {
return false;
}
const o = object as any;
if (typeof o.modStatus === 'undefined') {
return true;
}
switch (o.modStatus) {
case ModerationStatus.NONE:
case ModerationStatus.PASSED:
return true;
case ModerationStatus.NOT_PASSED:
case ModerationStatus.PRE:
return false;
case ModerationStatus.POST:
if (o.expiresDate) {
const now = new Date();
return o.expiresDate > now.getTime();
} else if (o.ttl && o.createdDate) {
const now = new Date();
const expires = o.createdDate + o.ttl * 60 * 1000;
return expires > now.getTime();
}
return false;
}
return true;
}
export enum OrderBy {
SCORE = 'SCORE',
CREATED_DATE = 'CREATED_DATE',
VIEWS = 'VIEWS',
VOTE_AVERAGE = 'VOTE_AVERAGE'
}
export interface Search {
q: string;
type: string;
author: any;
groupId: number;
/** Find objects with abuse reports */
hasAbuseReports?: boolean;
moderationVisibility: ModerationVisibility;
orderBy: OrderBy;
order: Order;
p: number; //page number
communityPermalink: string;
}
export interface SearchResult extends XcapJsonResult {
/** Results */
results: PaginatedCollection<XcapObject>;
/** Number of abuse reports */
nAbuseReports: number;
/** Number of objects awaiting moderation */
nAwaitingModeration: number;
/** Number of objects where moderation has expired */
nModerationExpired: number;
/** Maps from community user id to stackend user */
adminUserMapping: { [id: number]: User };
/** Maps from obfuscatedReference to result from content filtering results */
contentFilterResults: { [obfuscatedReference: string]: ContentFilterResults };
/** Stop words found in the result. Maps from obfuscatedReference to word */
stopWords: {
[obfuscatedReference: string]: string;
};
}
/**
* Search for objects to moderate.
*
* This search can find all objects in the system. The default is to only show objects that requires moderation.
*
* @param q {String} Search expression
* @param p {number} Page number
* @param type {String} all|article|comment|group|...
* @param groupIds {number}
* @param moderationVisibility {moderationVisibility} Default: ModerationVisibility.MODERATION_PENDING
* @param orderBy {orderBy} Default: CREATED_DATE
* @param order {order} Default: ASCENDING
* @param communityPermalink type {String}
* @return {Promise}
*/
export function search({
q,
type = 'all',
author,
groupId,
moderationVisibility = ModerationVisibility.MODERATION_PENDING,
orderBy = OrderBy.CREATED_DATE,
order = Order.ASCENDING,
communityPermalink,
p
}: Search): Thunk<Promise<SearchResult>> {
!!arguments[0].communityPermalink && delete arguments[0].communityPermalink;
return getJson({ url: '/admin/search', parameters: arguments, community: communityPermalink });
}
export type SetModStatus = {
obfuscatedReference: string;
approved: boolean;
};
/**
* Change moderation status for a single object.
*
* @param {String} obfuscatedReference
* @param {Boolean} approved
* @return {Promise}
*/
export function setModStatus({ obfuscatedReference, approved }: SetModStatus): Thunk<Promise<XcapJsonResult>> {
return post({ url: '/admin/moderate', parameters: arguments });
}
export type SetModStatuses = {
obfuscatedReferences: Array<string>;
approved: boolean;
};
/**
* Change moderation status for multiple objects.
*
* @param obfuscatedReferences {Array} A list of obfuscatedReference
* @param approved {Boolean}
* @return {Promise}
*/
export function setModStatuses({ obfuscatedReferences, approved }: SetModStatuses): Thunk<Promise<XcapJsonResult>> {
return post({ url: '/admin/moderate-multiple', parameters: arguments });
}