mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-03-22 12:33:11 -04:00
refactor(frontend): replace legacy settings init/settings pattern with typed config functions
This commit is contained in:
@@ -1,59 +0,0 @@
|
|||||||
const urlParse = require('url-parse');
|
|
||||||
|
|
||||||
let BASE_URL = null;
|
|
||||||
let ENDPOINTS = null;
|
|
||||||
|
|
||||||
function endpointsIter(ret, endpoints) {
|
|
||||||
const baseUrl = BASE_URL.toString().replace(/\/+$/, '');
|
|
||||||
|
|
||||||
for (let k in endpoints) {
|
|
||||||
if ('string' === typeof endpoints[k]) {
|
|
||||||
ret[k] = baseUrl + '/' + endpoints[k].replace(/^\//g, '');
|
|
||||||
} else {
|
|
||||||
endpointsIter(ret[k], endpoints[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatEndpoints(endpoints) {
|
|
||||||
const baseUrl = BASE_URL.toString();
|
|
||||||
const ret = endpoints;
|
|
||||||
endpointsIter(ret, endpoints);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function init(base_url, endpoints) {
|
|
||||||
BASE_URL = urlParse(base_url);
|
|
||||||
|
|
||||||
ENDPOINTS = formatEndpoints({
|
|
||||||
media: endpoints.media,
|
|
||||||
featured: endpoints.media + '?show=featured',
|
|
||||||
recommended: endpoints.media + '?show=recommended',
|
|
||||||
playlists: endpoints.playlists,
|
|
||||||
users: endpoints.members,
|
|
||||||
user: {
|
|
||||||
liked: endpoints.liked,
|
|
||||||
history: endpoints.history,
|
|
||||||
playlists: endpoints.playlists + '?author=',
|
|
||||||
},
|
|
||||||
archive: {
|
|
||||||
tags: endpoints.tags,
|
|
||||||
categories: endpoints.categories,
|
|
||||||
},
|
|
||||||
manage: {
|
|
||||||
media: endpoints.manage_media,
|
|
||||||
users: endpoints.manage_users,
|
|
||||||
comments: endpoints.manage_comments,
|
|
||||||
},
|
|
||||||
search: {
|
|
||||||
query: endpoints.search + '?q=',
|
|
||||||
titles: endpoints.search + '?show=titles&q=',
|
|
||||||
tag: endpoints.search + '?t=',
|
|
||||||
category: endpoints.search + '?c=',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function endpoints() {
|
|
||||||
return ENDPOINTS;
|
|
||||||
}
|
|
||||||
45
frontend/src/static/js/utils/settings/api.ts
Executable file
45
frontend/src/static/js/utils/settings/api.ts
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
import urlParse from 'url-parse'; // @todo: It's not necessary, 'URL.parse(...)' is sufficient
|
||||||
|
import { GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
function formatEndpoints<K extends string = string>(baseUrl: string, endpoints: Record<K, string>) {
|
||||||
|
for (let k in endpoints) {
|
||||||
|
endpoints[k] = baseUrl + '/' + endpoints[k].replace(/^\//g, '');
|
||||||
|
}
|
||||||
|
return endpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function apiConfig(
|
||||||
|
apiUrl: GlobalMediaCMS['site']['api'],
|
||||||
|
endpoints: GlobalMediaCMS['api']
|
||||||
|
): MediaCMSConfig['api'] {
|
||||||
|
const baseUrl = urlParse(apiUrl).toString().replace(/\/+$/, '');
|
||||||
|
return {
|
||||||
|
...formatEndpoints(baseUrl, {
|
||||||
|
media: endpoints.media,
|
||||||
|
featured: endpoints.media + '?show=featured',
|
||||||
|
recommended: endpoints.media + '?show=recommended',
|
||||||
|
playlists: endpoints.playlists,
|
||||||
|
users: endpoints.members,
|
||||||
|
}),
|
||||||
|
user: formatEndpoints(baseUrl, {
|
||||||
|
liked: endpoints.liked,
|
||||||
|
history: endpoints.history,
|
||||||
|
playlists: endpoints.playlists + '?author=',
|
||||||
|
}),
|
||||||
|
archive: formatEndpoints(baseUrl, {
|
||||||
|
tags: endpoints.tags,
|
||||||
|
categories: endpoints.categories,
|
||||||
|
}),
|
||||||
|
manage: formatEndpoints(baseUrl, {
|
||||||
|
media: endpoints.manage_media,
|
||||||
|
users: endpoints.manage_users,
|
||||||
|
comments: endpoints.manage_comments,
|
||||||
|
}),
|
||||||
|
search: formatEndpoints(baseUrl, {
|
||||||
|
query: endpoints.search + '?q=',
|
||||||
|
titles: endpoints.search + '?show=titles&q=',
|
||||||
|
tag: endpoints.search + '?t=',
|
||||||
|
category: endpoints.search + '?c=',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import * as api from './api.js';
|
|
||||||
import * as media from './media.js';
|
|
||||||
import * as site from './site.js';
|
|
||||||
import * as theme from './theme.js';
|
|
||||||
import * as url from './url.js';
|
|
||||||
import * as member from './member.js';
|
|
||||||
import * as contents from './contents.js';
|
|
||||||
import * as pages from './pages.js';
|
|
||||||
import * as sidebar from './sidebar.js';
|
|
||||||
import * as taxonomies from './taxonomies.js';
|
|
||||||
import * as optionsPages from './optionsPages.js';
|
|
||||||
import * as optionsEmbedded from './optionsEmbedded.js';
|
|
||||||
import * as playlists from './playlists.js';
|
|
||||||
import * as notifications from './notifications.js';
|
|
||||||
|
|
||||||
let DATA = null;
|
|
||||||
|
|
||||||
export function config(glbl) {
|
|
||||||
if (DATA) {
|
|
||||||
return DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
pages.init({ ...glbl.site.pages, ...glbl.site.userPages });
|
|
||||||
optionsPages.init(glbl.pages.home, glbl.pages.search, glbl.pages.media, glbl.pages.profile, pages.settings());
|
|
||||||
|
|
||||||
url.init({
|
|
||||||
home: glbl.url.home,
|
|
||||||
admin: !glbl.user.is.anonymous && glbl.user.is.admin ? glbl.url.admin : '',
|
|
||||||
error404: glbl.url.error404,
|
|
||||||
embed: glbl.site.url.replace(/\/+$/, '') + '/embed?m=',
|
|
||||||
latest: glbl.url.latestMedia,
|
|
||||||
featured: glbl.url.featuredMedia,
|
|
||||||
recommended: glbl.url.recommendedMedia,
|
|
||||||
signin: glbl.url.signin,
|
|
||||||
signout: !glbl.user.is.anonymous ? glbl.url.signout : '',
|
|
||||||
register: glbl.url.register,
|
|
||||||
changePassword: !glbl.user.is.anonymous ? glbl.url.changePassword : '',
|
|
||||||
members: glbl.url.members,
|
|
||||||
search: {
|
|
||||||
base: glbl.url.search,
|
|
||||||
query: glbl.url.search + '?q=',
|
|
||||||
tag: glbl.url.search + '?t=',
|
|
||||||
category: glbl.url.search + '?c=',
|
|
||||||
},
|
|
||||||
profile: !!glbl.site.devEnv
|
|
||||||
? {
|
|
||||||
media: glbl.user.pages.media,
|
|
||||||
about: glbl.user.pages.about,
|
|
||||||
playlists: glbl.user.pages.playlists,
|
|
||||||
shared_by_me: glbl.user.pages.media + '/shared_by_me',
|
|
||||||
shared_with_me: glbl.user.pages.media + '/shared_with_me',
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
media: glbl.site.url.replace(/\/$/, '') + '/user/' + glbl.profileId,
|
|
||||||
about: glbl.site.url.replace(/\/$/, '') + '/user/' + glbl.profileId + '/about',
|
|
||||||
playlists: glbl.site.url.replace(/\/$/, '') + '/user/' + glbl.profileId + '/playlists',
|
|
||||||
shared_by_me: glbl.site.url.replace(/\/$/, '') + '/user/' + glbl.profileId + '/shared_by_me',
|
|
||||||
shared_with_me: glbl.site.url.replace(/\/$/, '') + '/user/' + glbl.profileId + '/shared_with_me',
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
liked: glbl.url.likedMedia,
|
|
||||||
history: glbl.url.history,
|
|
||||||
addMedia: glbl.url.addMedia,
|
|
||||||
editChannel: glbl.url.editChannel,
|
|
||||||
editProfile: glbl.url.editProfile,
|
|
||||||
},
|
|
||||||
archive: {
|
|
||||||
tags: glbl.url.tags,
|
|
||||||
categories: glbl.url.categories,
|
|
||||||
},
|
|
||||||
manage: {
|
|
||||||
media: !glbl.user.is.anonymous ? glbl.url.manageMedia : '',
|
|
||||||
users: !glbl.user.is.anonymous ? glbl.url.manageUsers : '',
|
|
||||||
comments: !glbl.user.is.anonymous ? glbl.url.manageComments : '',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
site.init(glbl.site);
|
|
||||||
contents.init(glbl.contents);
|
|
||||||
api.init(glbl.site.api, glbl.api);
|
|
||||||
sidebar.init(glbl.features.sideBar);
|
|
||||||
taxonomies.init(glbl.site.taxonomies);
|
|
||||||
member.init(glbl.user, glbl.features);
|
|
||||||
theme.init(glbl.site.theme, glbl.site.logo);
|
|
||||||
optionsEmbedded.init(glbl.features.embeddedVideo);
|
|
||||||
media.init(glbl.features.mediaItem, glbl.features.media.shareOptions);
|
|
||||||
playlists.init(glbl.features.playlists);
|
|
||||||
|
|
||||||
notifications.init(glbl.contents.notifications);
|
|
||||||
|
|
||||||
DATA = {
|
|
||||||
site: site.settings(),
|
|
||||||
theme: theme.settings(),
|
|
||||||
member: member.settings(),
|
|
||||||
media: media.settings(),
|
|
||||||
playlists: playlists.settings(),
|
|
||||||
url: url.pages(),
|
|
||||||
api: api.endpoints(),
|
|
||||||
sidebar: sidebar.settings(),
|
|
||||||
contents: contents.settings(),
|
|
||||||
options: {
|
|
||||||
pages: optionsPages.settings(),
|
|
||||||
embedded: optionsEmbedded.settings(),
|
|
||||||
},
|
|
||||||
enabled: {
|
|
||||||
pages: pages.settings(),
|
|
||||||
taxonomies: taxonomies.settings(),
|
|
||||||
},
|
|
||||||
notifications: notifications.settings(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return DATA;
|
|
||||||
}
|
|
||||||
50
frontend/src/static/js/utils/settings/config.ts
Normal file
50
frontend/src/static/js/utils/settings/config.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
import { apiConfig } from './api';
|
||||||
|
import { contentsConfig } from './contents';
|
||||||
|
import { mediaConfig } from './media';
|
||||||
|
import { memberConfig } from './member';
|
||||||
|
import { notificationsConfig } from './notifications';
|
||||||
|
import { optionsEmbeddedConfig } from './optionsEmbedded';
|
||||||
|
import { optionsPagesConfig } from './optionsPages';
|
||||||
|
import { pagesConfig } from './pages';
|
||||||
|
import { playlistsConfig } from './playlists';
|
||||||
|
import { sidebarConfig } from './sidebar';
|
||||||
|
import { siteConfig } from './site';
|
||||||
|
import { taxonomiesConfig } from './taxonomies';
|
||||||
|
import { themeConfig } from './theme';
|
||||||
|
import { urlConfig } from './url';
|
||||||
|
|
||||||
|
let DATA: MediaCMSConfig | null = null;
|
||||||
|
|
||||||
|
export function config(globalObj: GlobalMediaCMS) {
|
||||||
|
if (DATA) {
|
||||||
|
return DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { api, contents, features, pages, site, user } = globalObj;
|
||||||
|
|
||||||
|
const enabledPages = pagesConfig({ ...site.pages, ...site.userPages });
|
||||||
|
|
||||||
|
DATA = {
|
||||||
|
api: apiConfig(site.api, api),
|
||||||
|
contents: contentsConfig(contents),
|
||||||
|
enabled: {
|
||||||
|
pages: enabledPages,
|
||||||
|
taxonomies: taxonomiesConfig(site.taxonomies),
|
||||||
|
},
|
||||||
|
media: mediaConfig(features.mediaItem, features.media.shareOptions),
|
||||||
|
member: memberConfig(user, features),
|
||||||
|
notifications: notificationsConfig(contents.notifications),
|
||||||
|
options: {
|
||||||
|
pages: optionsPagesConfig(pages.home, pages.search, pages.media, pages.profile, enabledPages),
|
||||||
|
embedded: optionsEmbeddedConfig(features.embeddedVideo),
|
||||||
|
},
|
||||||
|
playlists: playlistsConfig(features.playlists),
|
||||||
|
sidebar: sidebarConfig(features.sideBar),
|
||||||
|
site: siteConfig(site),
|
||||||
|
theme: themeConfig(site.theme, site.logo),
|
||||||
|
url: urlConfig(globalObj),
|
||||||
|
};
|
||||||
|
|
||||||
|
return DATA;
|
||||||
|
}
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
let CONTENTS = null;
|
|
||||||
|
|
||||||
function headerContents(contents) {
|
|
||||||
const ret = {
|
|
||||||
right: '',
|
|
||||||
onLogoRight: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== contents) {
|
|
||||||
if ('string' === typeof contents.right) {
|
|
||||||
ret.right = contents.right.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof contents.onLogoRight) {
|
|
||||||
ret.onLogoRight = contents.onLogoRight.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sidebarContents(contents) {
|
|
||||||
const ret = {
|
|
||||||
navMenu: {
|
|
||||||
items: [],
|
|
||||||
},
|
|
||||||
mainMenuExtra: {
|
|
||||||
items: [],
|
|
||||||
},
|
|
||||||
belowNavMenu: '',
|
|
||||||
belowThemeSwitcher: '',
|
|
||||||
footer: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (undefined !== contents) {
|
|
||||||
if (undefined !== contents.mainMenuExtraItems) {
|
|
||||||
let i = 0;
|
|
||||||
while (i < contents.mainMenuExtraItems.length) {
|
|
||||||
if (
|
|
||||||
'string' === typeof contents.mainMenuExtraItems[i].text &&
|
|
||||||
'string' === typeof contents.mainMenuExtraItems[i].link &&
|
|
||||||
'string' === typeof contents.mainMenuExtraItems[i].icon
|
|
||||||
) {
|
|
||||||
ret.mainMenuExtra.items.push({
|
|
||||||
text: contents.mainMenuExtraItems[i].text,
|
|
||||||
link: contents.mainMenuExtraItems[i].link,
|
|
||||||
icon: contents.mainMenuExtraItems[i].icon,
|
|
||||||
className: contents.mainMenuExtraItems[i].className,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (undefined !== contents.navMenuItems) {
|
|
||||||
let i = 0;
|
|
||||||
while (i < contents.navMenuItems.length) {
|
|
||||||
if (
|
|
||||||
'string' === typeof contents.navMenuItems[i].text &&
|
|
||||||
'string' === typeof contents.navMenuItems[i].link &&
|
|
||||||
'string' === typeof contents.navMenuItems[i].icon
|
|
||||||
) {
|
|
||||||
ret.navMenu.items.push({
|
|
||||||
text: contents.navMenuItems[i].text,
|
|
||||||
link: contents.navMenuItems[i].link,
|
|
||||||
icon: contents.navMenuItems[i].icon,
|
|
||||||
className: contents.navMenuItems[i].className,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof contents.belowNavMenu) {
|
|
||||||
ret.belowNavMenu = contents.belowNavMenu.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof contents.belowThemeSwitcher) {
|
|
||||||
ret.belowThemeSwitcher = contents.belowThemeSwitcher.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof contents.footer) {
|
|
||||||
ret.footer = contents.footer.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
function uploaderContents(contents) {
|
|
||||||
const ret = {
|
|
||||||
belowUploadArea: '',
|
|
||||||
postUploadMessage: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== contents) {
|
|
||||||
if ('string' === typeof contents.belowUploadArea) {
|
|
||||||
ret.belowUploadArea = contents.belowUploadArea.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof contents.postUploadMessage) {
|
|
||||||
ret.postUploadMessage = contents.postUploadMessage.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function init(contents) {
|
|
||||||
CONTENTS = {
|
|
||||||
header: headerContents(contents.header),
|
|
||||||
sidebar: sidebarContents(contents.sidebar),
|
|
||||||
uploader: uploaderContents(contents.uploader),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return CONTENTS;
|
|
||||||
}
|
|
||||||
67
frontend/src/static/js/utils/settings/contents.ts
Executable file
67
frontend/src/static/js/utils/settings/contents.ts
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
const headerContents = (settings?: DeepPartial<GlobalMediaCMS['contents']['header']>) => ({
|
||||||
|
right: settings?.right !== undefined ? settings.right.trim() : '',
|
||||||
|
onLogoRight: settings?.onLogoRight !== undefined ? settings.onLogoRight.trim() : '',
|
||||||
|
});
|
||||||
|
|
||||||
|
function sidebarContents(settings?: DeepPartial<GlobalMediaCMS['contents']['sidebar']>) {
|
||||||
|
const sidebar: MediaCMSConfig['contents']['sidebar'] = {
|
||||||
|
belowNavMenu: settings?.belowNavMenu ? settings.belowNavMenu.trim() : '',
|
||||||
|
belowThemeSwitcher: settings?.belowThemeSwitcher ? settings.belowThemeSwitcher.trim() : '',
|
||||||
|
footer: settings?.footer ? settings.footer.trim() : '',
|
||||||
|
mainMenuExtra: { items: [] },
|
||||||
|
navMenu: { items: [] },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (settings?.mainMenuExtraItems) {
|
||||||
|
for (const item of settings.mainMenuExtraItems) {
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = item.text ? item.text.trim() : '';
|
||||||
|
const link = item.link ? item.link.trim() : '';
|
||||||
|
const icon = item.icon ? item.icon.trim() : '';
|
||||||
|
|
||||||
|
const className = item.className ? item.className.trim() : '';
|
||||||
|
|
||||||
|
if (text && link && icon) {
|
||||||
|
sidebar.mainMenuExtra.items.push({ text, link, icon, className });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings?.navMenuItems) {
|
||||||
|
for (const item of settings.navMenuItems) {
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = item.text ? item.text.trim() : '';
|
||||||
|
const link = item.link ? item.link.trim() : '';
|
||||||
|
const icon = item.icon ? item.icon.trim() : '';
|
||||||
|
|
||||||
|
const className = item.className ? item.className.trim() : '';
|
||||||
|
|
||||||
|
if (text && link && icon) {
|
||||||
|
sidebar.navMenu.items.push({ text, link, icon, className });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sidebar;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploaderContents = (settings?: DeepPartial<GlobalMediaCMS['contents']['uploader']>) => ({
|
||||||
|
belowUploadArea: settings?.belowUploadArea ? settings?.belowUploadArea.trim() : '',
|
||||||
|
postUploadMessage: settings?.postUploadMessage ? settings?.postUploadMessage.trim() : '',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const contentsConfig = (
|
||||||
|
settings?: DeepPartial<Omit<GlobalMediaCMS['contents'], 'notifications'>>
|
||||||
|
): MediaCMSConfig['contents'] => ({
|
||||||
|
header: headerContents(settings?.header),
|
||||||
|
sidebar: sidebarContents(settings?.sidebar),
|
||||||
|
uploader: uploaderContents(settings?.uploader),
|
||||||
|
});
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
let MEDIA = null;
|
|
||||||
|
|
||||||
export function init(item, shareOptions) {
|
|
||||||
MEDIA = {
|
|
||||||
item: {
|
|
||||||
displayAuthor: true,
|
|
||||||
displayViews: true,
|
|
||||||
displayPublishDate: true,
|
|
||||||
},
|
|
||||||
share: {
|
|
||||||
options: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== item) {
|
|
||||||
|
|
||||||
if (true === item.hideAuthor) {
|
|
||||||
MEDIA.item.displayAuthor = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === item.hideViews) {
|
|
||||||
MEDIA.item.displayViews = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === item.hideDate) {
|
|
||||||
MEDIA.item.displayPublishDate = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== shareOptions) {
|
|
||||||
const validShareOptions = [
|
|
||||||
'embed',
|
|
||||||
'email',
|
|
||||||
];
|
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
while (i < shareOptions.length) {
|
|
||||||
if (-1 < validShareOptions.indexOf(shareOptions[i])) {
|
|
||||||
MEDIA.share.options.push(shareOptions[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return MEDIA;
|
|
||||||
}
|
|
||||||
33
frontend/src/static/js/utils/settings/media.ts
Executable file
33
frontend/src/static/js/utils/settings/media.ts
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export function mediaConfig(
|
||||||
|
item?: DeepPartial<GlobalMediaCMS['features']['mediaItem']>,
|
||||||
|
shareOptions?: DeepPartial<GlobalMediaCMS['features']['media']['shareOptions']>
|
||||||
|
) {
|
||||||
|
const ret: MediaCMSConfig['media'] = {
|
||||||
|
item: {
|
||||||
|
displayAuthor: item?.hideAuthor === true ? false : true,
|
||||||
|
displayViews: item?.hideViews === true ? false : true,
|
||||||
|
displayPublishDate: item?.hideDate === true ? false : true,
|
||||||
|
},
|
||||||
|
share: { options: [] },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (shareOptions) {
|
||||||
|
const validShareOptions = ['embed', 'email']; // @todo: Check this
|
||||||
|
|
||||||
|
for (const option of shareOptions) {
|
||||||
|
if (!option) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const opt = option.trim();
|
||||||
|
|
||||||
|
if (validShareOptions.includes(opt)) {
|
||||||
|
ret.share.options.push(opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
let MEMBER = null;
|
|
||||||
|
|
||||||
export function init(user, features) {
|
|
||||||
MEMBER = {
|
|
||||||
name: null,
|
|
||||||
username: null,
|
|
||||||
thumbnail: null,
|
|
||||||
is: {
|
|
||||||
admin: false,
|
|
||||||
anonymous: true,
|
|
||||||
},
|
|
||||||
can: {
|
|
||||||
login: true,
|
|
||||||
register: true,
|
|
||||||
addMedia: false,
|
|
||||||
editProfile: false,
|
|
||||||
canSeeMembersPage: true,
|
|
||||||
usersNeedsToBeApproved: true,
|
|
||||||
changePassword: true,
|
|
||||||
deleteProfile: false,
|
|
||||||
readComment: true,
|
|
||||||
addComment: false,
|
|
||||||
mentionComment: false,
|
|
||||||
deleteComment: false,
|
|
||||||
editMedia: false,
|
|
||||||
deleteMedia: false,
|
|
||||||
editSubtitle: false,
|
|
||||||
manageMedia: false,
|
|
||||||
manageUsers: false,
|
|
||||||
manageComments: false,
|
|
||||||
reportMedia: false,
|
|
||||||
downloadMedia: false,
|
|
||||||
saveMedia: false,
|
|
||||||
likeMedia: true,
|
|
||||||
dislikeMedia: true,
|
|
||||||
shareMedia: true,
|
|
||||||
contactUser: false,
|
|
||||||
},
|
|
||||||
pages: {
|
|
||||||
home: null,
|
|
||||||
about: null,
|
|
||||||
media: null,
|
|
||||||
playlists: null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== user) {
|
|
||||||
MEMBER.is.anonymous = true === user.is.anonymous ? true : false;
|
|
||||||
|
|
||||||
if (!MEMBER.is.anonymous) {
|
|
||||||
MEMBER.is.admin = true === user.is.admin;
|
|
||||||
|
|
||||||
MEMBER.name = 'string' === typeof user.name ? user.name.trim() : '';
|
|
||||||
MEMBER.name = '' === MEMBER.name ? null : MEMBER.name;
|
|
||||||
|
|
||||||
MEMBER.username = 'string' === typeof user.username ? user.username.trim() : '';
|
|
||||||
MEMBER.username = '' === MEMBER.username ? null : MEMBER.username;
|
|
||||||
|
|
||||||
MEMBER.thumbnail = 'string' === typeof user.thumbnail ? user.thumbnail.trim() : '';
|
|
||||||
MEMBER.thumbnail = '' === MEMBER.thumbnail ? null : MEMBER.thumbnail;
|
|
||||||
|
|
||||||
MEMBER.can.changePassword = false === user.can.changePassword ? false : MEMBER.can.changePassword;
|
|
||||||
|
|
||||||
MEMBER.can.deleteProfile = true === user.can.deleteProfile;
|
|
||||||
MEMBER.can.addComment = true === user.can.addComment;
|
|
||||||
MEMBER.can.mentionComment = true === user.can.mentionComment;
|
|
||||||
MEMBER.can.deleteComment = true === user.can.deleteComment;
|
|
||||||
MEMBER.can.editMedia = true === user.can.editMedia;
|
|
||||||
MEMBER.can.deleteMedia = true === user.can.deleteMedia;
|
|
||||||
MEMBER.can.editSubtitle = true === user.can.editSubtitle;
|
|
||||||
MEMBER.can.manageMedia = true === user.can.manageMedia;
|
|
||||||
MEMBER.can.manageUsers = true === user.can.manageUsers;
|
|
||||||
MEMBER.can.manageComments = true === user.can.manageComments;
|
|
||||||
|
|
||||||
MEMBER.can.contactUser = true === user.can.contactUser;
|
|
||||||
|
|
||||||
if (void 0 !== user.pages) {
|
|
||||||
|
|
||||||
if ('string' === typeof user.pages.about) {
|
|
||||||
MEMBER.pages.about = user.pages.about.trim();
|
|
||||||
MEMBER.pages.about = '' === MEMBER.pages.about ? null : MEMBER.pages.about;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof user.pages.media) {
|
|
||||||
MEMBER.pages.media = user.pages.media.trim();
|
|
||||||
MEMBER.pages.media = '' === MEMBER.pages.media ? null : MEMBER.pages.media;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof user.pages.playlists) {
|
|
||||||
MEMBER.pages.playlists = user.pages.playlists.trim();
|
|
||||||
MEMBER.pages.playlists = '' === MEMBER.pages.playlists ? null : MEMBER.pages.playlists;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MEMBER.can.canSeeMembersPage = true === user.can.canSeeMembersPage;
|
|
||||||
MEMBER.can.usersNeedsToBeApproved = true === user.can.usersNeedsToBeApproved;
|
|
||||||
MEMBER.can.addMedia = true === user.can.addMedia;
|
|
||||||
MEMBER.can.editProfile = true === user.can.editProfile;
|
|
||||||
MEMBER.can.readComment = false === user.can.readComment ? false : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== features) {
|
|
||||||
if (void 0 !== features.media) {
|
|
||||||
if (void 0 !== features.media.actions) {
|
|
||||||
const mediaActions = features.media.actions;
|
|
||||||
|
|
||||||
MEMBER.can.addComment = MEMBER.can.addComment && true === mediaActions.comment;
|
|
||||||
MEMBER.can.mentionComment = MEMBER.can.mentionComment && true === mediaActions.comment_mention;
|
|
||||||
|
|
||||||
MEMBER.can.likeMedia = false === mediaActions.like ? false : true;
|
|
||||||
MEMBER.can.dislikeMedia = false === mediaActions.dislike ? false : true;
|
|
||||||
MEMBER.can.reportMedia = false === mediaActions.report ? false : true;
|
|
||||||
|
|
||||||
MEMBER.can.downloadMedia = true === mediaActions.download;
|
|
||||||
MEMBER.can.saveMedia = true === mediaActions.save;
|
|
||||||
MEMBER.can.shareMedia = true === mediaActions.share;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== features.headerBar) {
|
|
||||||
if (true === features.headerBar.hideLogin) {
|
|
||||||
MEMBER.can.login = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === features.headerBar.hideRegister) {
|
|
||||||
MEMBER.can.register = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return MEMBER;
|
|
||||||
}
|
|
||||||
98
frontend/src/static/js/utils/settings/member.ts
Executable file
98
frontend/src/static/js/utils/settings/member.ts
Executable file
@@ -0,0 +1,98 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export function memberConfig(
|
||||||
|
user?: DeepPartial<GlobalMediaCMS['user']>,
|
||||||
|
features?: {
|
||||||
|
headerBar?: DeepPartial<GlobalMediaCMS['features']['headerBar']>;
|
||||||
|
media?: { actions?: DeepPartial<GlobalMediaCMS['features']['media']['actions']> };
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const ret: MediaCMSConfig['member'] = {
|
||||||
|
name: null,
|
||||||
|
username: null,
|
||||||
|
thumbnail: null,
|
||||||
|
is: { admin: false, anonymous: true },
|
||||||
|
can: {
|
||||||
|
login: true,
|
||||||
|
register: true,
|
||||||
|
addMedia: false,
|
||||||
|
editProfile: false,
|
||||||
|
canSeeMembersPage: true,
|
||||||
|
usersNeedsToBeApproved: true,
|
||||||
|
changePassword: true,
|
||||||
|
deleteProfile: false,
|
||||||
|
readComment: true,
|
||||||
|
addComment: false,
|
||||||
|
mentionComment: false,
|
||||||
|
deleteComment: false,
|
||||||
|
editMedia: false,
|
||||||
|
deleteMedia: false,
|
||||||
|
editSubtitle: false,
|
||||||
|
manageMedia: false,
|
||||||
|
manageUsers: false,
|
||||||
|
manageComments: false,
|
||||||
|
reportMedia: false,
|
||||||
|
downloadMedia: false,
|
||||||
|
saveMedia: false,
|
||||||
|
likeMedia: true,
|
||||||
|
dislikeMedia: true,
|
||||||
|
shareMedia: true,
|
||||||
|
contactUser: false,
|
||||||
|
},
|
||||||
|
pages: { home: null, about: null, media: null, playlists: null },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
ret.is.anonymous = user.is?.anonymous === false ? false : true;
|
||||||
|
|
||||||
|
if (!ret.is.anonymous) {
|
||||||
|
ret.is.admin = user.is?.admin === true;
|
||||||
|
|
||||||
|
ret.name = (user.name ? user.name.trim() : null) || null;
|
||||||
|
ret.username = (user.username ? user.username.trim() : null) || null;
|
||||||
|
ret.thumbnail = (user.thumbnail ? user.thumbnail.trim() : null) || null;
|
||||||
|
ret.can.changePassword = user.can?.changePassword === false ? false : true;
|
||||||
|
|
||||||
|
ret.can.deleteProfile = user.can?.deleteProfile === true;
|
||||||
|
ret.can.addComment = user.can?.addComment === true;
|
||||||
|
ret.can.mentionComment = user.can?.mentionComment === true;
|
||||||
|
ret.can.deleteComment = user.can?.deleteComment === true;
|
||||||
|
ret.can.editMedia = user.can?.editMedia === true;
|
||||||
|
ret.can.deleteMedia = user.can?.deleteMedia === true;
|
||||||
|
ret.can.editSubtitle = user.can?.editSubtitle === true;
|
||||||
|
ret.can.manageMedia = user.can?.manageMedia === true;
|
||||||
|
ret.can.manageUsers = user.can?.manageUsers === true;
|
||||||
|
ret.can.manageComments = user.can?.manageComments === true;
|
||||||
|
ret.can.contactUser = user.can?.contactUser === true;
|
||||||
|
|
||||||
|
ret.pages.about = (user.pages?.about ? user.pages.about.trim() : null) || null;
|
||||||
|
ret.pages.media = (user.pages?.media ? user.pages.media.trim() : null) || null;
|
||||||
|
ret.pages.playlists = (user.pages?.playlists ? user.pages.playlists.trim() : null) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.can.canSeeMembersPage = user.can?.canSeeMembersPage === false ? false : true;
|
||||||
|
ret.can.usersNeedsToBeApproved = user.can?.usersNeedsToBeApproved === false ? false : true;
|
||||||
|
ret.can.addMedia = user.can?.addMedia === true;
|
||||||
|
ret.can.editProfile = user.can?.editProfile === true;
|
||||||
|
ret.can.readComment = user.can?.readComment === false ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mediaActions = features?.media?.actions;
|
||||||
|
if (mediaActions !== undefined) {
|
||||||
|
ret.can.addComment = ret.can.addComment && mediaActions?.comment === true;
|
||||||
|
ret.can.mentionComment = ret.can.mentionComment && mediaActions?.comment_mention === true;
|
||||||
|
|
||||||
|
ret.can.likeMedia = mediaActions?.like === false ? false : true;
|
||||||
|
ret.can.dislikeMedia = mediaActions?.dislike === false ? false : true;
|
||||||
|
ret.can.reportMedia = mediaActions?.report === false ? false : true;
|
||||||
|
|
||||||
|
ret.can.downloadMedia = mediaActions?.download === true;
|
||||||
|
ret.can.saveMedia = mediaActions?.save === true;
|
||||||
|
ret.can.shareMedia = mediaActions?.share === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.can.login = features?.headerBar?.hideLogin === true ? false : true;
|
||||||
|
ret.can.register = features?.headerBar?.hideRegister === true ? false : true;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
let NOTIFICATIONS = null;
|
|
||||||
|
|
||||||
export function init(settings) {
|
|
||||||
NOTIFICATIONS = {
|
|
||||||
messages: {
|
|
||||||
addToLiked: 'Added to liked media',
|
|
||||||
removeFromLiked: 'Removed from liked media',
|
|
||||||
addToDisliked: 'Added to disliked media',
|
|
||||||
removeFromDisliked: 'Removed from disliked media',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let k, g;
|
|
||||||
|
|
||||||
if (void 0 !== settings) {
|
|
||||||
for (k in NOTIFICATIONS) {
|
|
||||||
if (void 0 !== settings[k]) {
|
|
||||||
if ('messages' === k) {
|
|
||||||
for (g in NOTIFICATIONS[k]) {
|
|
||||||
if ('string' === typeof settings[k][g]) {
|
|
||||||
NOTIFICATIONS[k][g] = settings[k][g];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return NOTIFICATIONS;
|
|
||||||
}
|
|
||||||
27
frontend/src/static/js/utils/settings/notifications.ts
Normal file
27
frontend/src/static/js/utils/settings/notifications.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export function notificationsConfig(settings?: DeepPartial<GlobalMediaCMS['contents']['notifications']>) {
|
||||||
|
const ret: MediaCMSConfig['notifications'] = {
|
||||||
|
messages: {
|
||||||
|
addToLiked: 'Added to liked media',
|
||||||
|
removeFromLiked: 'Removed from liked media',
|
||||||
|
addToDisliked: 'Added to disliked media',
|
||||||
|
removeFromDisliked: 'Removed from disliked media',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!settings?.messages) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entries = Object.entries(settings.messages) as [keyof typeof settings.messages, string][];
|
||||||
|
|
||||||
|
for (const [key, value] of entries) {
|
||||||
|
const message = value?.trim();
|
||||||
|
if (message) {
|
||||||
|
ret.messages[key] = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
let EMBEDDED = null;
|
|
||||||
|
|
||||||
export function init(embeddedVideo) {
|
|
||||||
EMBEDDED = {
|
|
||||||
video: {
|
|
||||||
dimensions: {
|
|
||||||
width: 560,
|
|
||||||
widthUnit: 'px', // Valid values: 'px', 'percent'
|
|
||||||
height: 315,
|
|
||||||
heightUnit: 'px', // Valid values: 'px', 'percent'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== embeddedVideo) {
|
|
||||||
if (void 0 !== embeddedVideo.initialDimensions) {
|
|
||||||
if (!isNaN(embeddedVideo.initialDimensions.width)) {
|
|
||||||
EMBEDDED.video.dimensions.width = embeddedVideo.initialDimensions.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof embeddedVideo.initialDimensions.widthUnit) {
|
|
||||||
if ('percent' === embeddedVideo.initialDimensions.widthUnit) {
|
|
||||||
embeddedVideo.initialDimensions.widthUnit = 'percent';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNaN(embeddedVideo.initialDimensions.height)) {
|
|
||||||
EMBEDDED.video.dimensions.height = embeddedVideo.initialDimensions.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof embeddedVideo.initialDimensions.heightUnit) {
|
|
||||||
if ('percent' === embeddedVideo.initialDimensions.heightUnit) {
|
|
||||||
embeddedVideo.initialDimensions.heightUnit = 'percent';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return EMBEDDED;
|
|
||||||
}
|
|
||||||
45
frontend/src/static/js/utils/settings/optionsEmbedded.ts
Executable file
45
frontend/src/static/js/utils/settings/optionsEmbedded.ts
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export function optionsEmbeddedConfig(settings?: DeepPartial<GlobalMediaCMS['features']['embeddedVideo']>) {
|
||||||
|
const ret: MediaCMSConfig['options']['embedded'] = {
|
||||||
|
video: {
|
||||||
|
dimensions: {
|
||||||
|
width: 560,
|
||||||
|
widthUnit: 'px',
|
||||||
|
height: 315,
|
||||||
|
heightUnit: 'px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!settings?.initialDimensions) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
// heightUnit, // @note: It doesn't used
|
||||||
|
// widthUnit // @note: It doesn't used
|
||||||
|
} = settings.initialDimensions;
|
||||||
|
|
||||||
|
if ('number' === typeof width && !Number.isNaN(width)) {
|
||||||
|
ret.video.dimensions.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('number' === typeof height && !Number.isNaN(height)) {
|
||||||
|
ret.video.dimensions.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @note: It doesn't used
|
||||||
|
// if (widthUnit?.trim() === 'percent') {
|
||||||
|
// settings.initialDimensions.widthUnit = 'percent';
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @note: It doesn't used
|
||||||
|
// if (heightUnit?.trim() === 'percent') {
|
||||||
|
// settings.initialDimensions.heightUnit = 'percent';
|
||||||
|
// }
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
let PAGES = null;
|
|
||||||
|
|
||||||
export function init(home, search, media, profile, VALID_PAGES) {
|
|
||||||
PAGES = {
|
|
||||||
home: {
|
|
||||||
sections: {
|
|
||||||
latest: {
|
|
||||||
title: '',
|
|
||||||
},
|
|
||||||
featured: {
|
|
||||||
title: '',
|
|
||||||
},
|
|
||||||
recommended: {
|
|
||||||
title: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
search: {
|
|
||||||
advancedFilters: false,
|
|
||||||
},
|
|
||||||
media: {
|
|
||||||
categoriesWithTitle: false,
|
|
||||||
htmlInDescription: false,
|
|
||||||
displayViews: true,
|
|
||||||
related: {
|
|
||||||
initialSize: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
profile: {
|
|
||||||
htmlInDescription: false,
|
|
||||||
includeHistory: false,
|
|
||||||
includeLikedMedia: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== home) {
|
|
||||||
if (void 0 !== home.sections) {
|
|
||||||
if (void 0 !== home.sections.latest) {
|
|
||||||
if ('string' === typeof home.sections.latest.title) {
|
|
||||||
PAGES.home.sections.latest.title = home.sections.latest.title.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== home.sections.featured) {
|
|
||||||
if ('string' === typeof home.sections.featured.title) {
|
|
||||||
PAGES.home.sections.featured.title = home.sections.featured.title.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== home.sections.recommended) {
|
|
||||||
if ('string' === typeof home.sections.recommended.title) {
|
|
||||||
PAGES.home.sections.recommended.title = home.sections.recommended.title.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== search) {
|
|
||||||
if (true === search.advancedFilters) {
|
|
||||||
PAGES.search.advancedFilters = search.advancedFilters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('' === PAGES.home.sections.latest.title) {
|
|
||||||
PAGES.home.sections.latest.title = void 0 !== VALID_PAGES.latest ? VALID_PAGES.latest.title : 'Latest';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('' === PAGES.home.sections.featured.title) {
|
|
||||||
PAGES.home.sections.featured.title = void 0 !== VALID_PAGES.featured ? VALID_PAGES.featured.title : 'Featured';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('' === PAGES.home.sections.recommended.title) {
|
|
||||||
PAGES.home.sections.recommended.title =
|
|
||||||
void 0 !== VALID_PAGES.recommended ? VALID_PAGES.recommended.title : 'Recommended';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== media) {
|
|
||||||
if (true === media.categoriesWithTitle) {
|
|
||||||
PAGES.media.categoriesWithTitle = media.categoriesWithTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === media.hideViews) {
|
|
||||||
PAGES.media.displayViews = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === media.htmlInDescription) {
|
|
||||||
PAGES.media.htmlInDescription = media.htmlInDescription;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== profile) {
|
|
||||||
if (true === profile.htmlInDescription) {
|
|
||||||
PAGES.profile.htmlInDescription = profile.htmlInDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === profile.includeHistory) {
|
|
||||||
PAGES.profile.includeHistory = profile.includeHistory;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === profile.includeLikedMedia) {
|
|
||||||
PAGES.profile.includeLikedMedia = profile.includeLikedMedia;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return PAGES;
|
|
||||||
}
|
|
||||||
63
frontend/src/static/js/utils/settings/optionsPages.ts
Executable file
63
frontend/src/static/js/utils/settings/optionsPages.ts
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export function optionsPagesConfig(
|
||||||
|
home?: DeepPartial<GlobalMediaCMS['pages']['home']>,
|
||||||
|
search?: DeepPartial<GlobalMediaCMS['pages']['search']>,
|
||||||
|
media?: DeepPartial<GlobalMediaCMS['pages']['media']>,
|
||||||
|
profile?: DeepPartial<GlobalMediaCMS['pages']['profile']>,
|
||||||
|
VALID_PAGES?: MediaCMSConfig['enabled']['pages']
|
||||||
|
) {
|
||||||
|
const ret: MediaCMSConfig['options']['pages'] = {
|
||||||
|
home: {
|
||||||
|
sections: {
|
||||||
|
latest: { title: VALID_PAGES?.latest?.title || 'Latest' },
|
||||||
|
featured: { title: VALID_PAGES?.featured?.title || 'Featured' },
|
||||||
|
recommended: { title: VALID_PAGES?.recommended?.title || 'Recommended' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
advancedFilters: search?.advancedFilters === true,
|
||||||
|
},
|
||||||
|
media: {
|
||||||
|
categoriesWithTitle: media?.categoriesWithTitle === true,
|
||||||
|
htmlInDescription: media?.htmlInDescription === true,
|
||||||
|
displayViews: media?.hideViews === true ? false : true,
|
||||||
|
related: {
|
||||||
|
initialSize:
|
||||||
|
'number' === typeof media?.related?.initialSize && !Number.isNaN(media.related.initialSize)
|
||||||
|
? media.related.initialSize
|
||||||
|
: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
profile: {
|
||||||
|
htmlInDescription: profile?.htmlInDescription === true,
|
||||||
|
includeHistory: profile?.includeHistory === true,
|
||||||
|
includeLikedMedia: profile?.includeLikedMedia === true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (home?.sections) {
|
||||||
|
if (typeof home.sections.latest?.title === 'string') {
|
||||||
|
const latestTitle = home.sections.latest.title.trim();
|
||||||
|
if (latestTitle !== '') {
|
||||||
|
ret.home.sections.latest.title = latestTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof home.sections.featured?.title === 'string') {
|
||||||
|
const featuredTitle = home.sections.featured.title.trim();
|
||||||
|
if (featuredTitle !== '') {
|
||||||
|
ret.home.sections.featured.title = featuredTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof home.sections.recommended?.title === 'string') {
|
||||||
|
const recommendedTitle = home.sections.recommended.title.trim();
|
||||||
|
if (recommendedTitle !== '') {
|
||||||
|
ret.home.sections.recommended.title = recommendedTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
let PAGES = null;
|
|
||||||
|
|
||||||
export function init(settings) {
|
|
||||||
PAGES = {
|
|
||||||
latest: {
|
|
||||||
enabled: false,
|
|
||||||
title: 'Recent uploads',
|
|
||||||
},
|
|
||||||
featured: {
|
|
||||||
enabled: false,
|
|
||||||
title: 'Featured',
|
|
||||||
},
|
|
||||||
recommended: {
|
|
||||||
enabled: false,
|
|
||||||
title: 'Recommended',
|
|
||||||
},
|
|
||||||
members: {
|
|
||||||
enabled: false,
|
|
||||||
title: 'Members',
|
|
||||||
},
|
|
||||||
liked: {
|
|
||||||
enabled: false,
|
|
||||||
title: 'Liked media',
|
|
||||||
},
|
|
||||||
history: {
|
|
||||||
enabled: false,
|
|
||||||
title: 'History',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== settings) {
|
|
||||||
for (let k in PAGES) {
|
|
||||||
if (void 0 !== settings[k]) {
|
|
||||||
PAGES[k].enabled = true;
|
|
||||||
|
|
||||||
if (void 0 !== settings[k].enabled && false === settings[k].enabled) {
|
|
||||||
PAGES[k].enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof settings[k].title) {
|
|
||||||
PAGES[k].title = settings[k].title.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return PAGES;
|
|
||||||
}
|
|
||||||
30
frontend/src/static/js/utils/settings/pages.ts
Executable file
30
frontend/src/static/js/utils/settings/pages.ts
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export function pagesConfig(
|
||||||
|
settings?: DeepPartial<GlobalMediaCMS['site']['pages']> & DeepPartial<GlobalMediaCMS['site']['userPages']>
|
||||||
|
) {
|
||||||
|
const ret: MediaCMSConfig['enabled']['pages'] = {
|
||||||
|
latest: { enabled: false, title: 'Recent uploads' },
|
||||||
|
featured: { enabled: false, title: 'Featured' },
|
||||||
|
recommended: { enabled: false, title: 'Recommended' },
|
||||||
|
members: { enabled: false, title: 'Members' },
|
||||||
|
liked: { enabled: false, title: 'Liked media' },
|
||||||
|
history: { enabled: false, title: 'History' },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let sk in settings) {
|
||||||
|
const key = sk as keyof typeof settings;
|
||||||
|
|
||||||
|
if (!ret[key]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[key].enabled = settings[key]?.enabled === false ? false : true;
|
||||||
|
|
||||||
|
if (settings[key]?.title !== undefined) {
|
||||||
|
ret[key].title = settings[key].title.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
let PLAYLISTS = null;
|
|
||||||
|
|
||||||
export function init(plists) {
|
|
||||||
PLAYLISTS = {
|
|
||||||
mediaTypes: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== plists) {
|
|
||||||
if (void 0 !== plists.mediaTypes) {
|
|
||||||
if (plists.mediaTypes.length) {
|
|
||||||
PLAYLISTS.mediaTypes = [];
|
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
while (i < plists.mediaTypes.length) {
|
|
||||||
switch (plists.mediaTypes[i]) {
|
|
||||||
case 'audio':
|
|
||||||
case 'video':
|
|
||||||
PLAYLISTS.mediaTypes.push(plists.mediaTypes[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PLAYLISTS.mediaTypes.length) {
|
|
||||||
PLAYLISTS.mediaTypes = ['audio', 'video'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return PLAYLISTS;
|
|
||||||
}
|
|
||||||
19
frontend/src/static/js/utils/settings/playlists.ts
Executable file
19
frontend/src/static/js/utils/settings/playlists.ts
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export function playlistsConfig(settings?: DeepPartial<GlobalMediaCMS['features']['playlists']>) {
|
||||||
|
const ret: MediaCMSConfig['playlists'] = { mediaTypes: [] };
|
||||||
|
|
||||||
|
if (Array.isArray(settings?.mediaTypes)) {
|
||||||
|
for (const mtype of settings.mediaTypes) {
|
||||||
|
if (mtype === 'audio' || mtype === 'video') {
|
||||||
|
ret.mediaTypes.push(mtype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret.mediaTypes.length === 0) {
|
||||||
|
ret.mediaTypes = ['audio', 'video'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
let SIDEBAR = null;
|
|
||||||
|
|
||||||
export function init(settings) {
|
|
||||||
SIDEBAR = {
|
|
||||||
hideHomeLink: false,
|
|
||||||
hideTagsLink: false,
|
|
||||||
hideCategoriesLink: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== settings) {
|
|
||||||
if ('boolean' === typeof settings.hideHomeLink) {
|
|
||||||
SIDEBAR.hideHomeLink = settings.hideHomeLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('boolean' === typeof settings.hideTagsLink) {
|
|
||||||
SIDEBAR.hideTagsLink = settings.hideTagsLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('boolean' === typeof settings.hideCategoriesLink) {
|
|
||||||
SIDEBAR.hideCategoriesLink = settings.hideCategoriesLink;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return SIDEBAR;
|
|
||||||
}
|
|
||||||
9
frontend/src/static/js/utils/settings/sidebar.ts
Normal file
9
frontend/src/static/js/utils/settings/sidebar.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export const sidebarConfig = (
|
||||||
|
settings?: DeepPartial<GlobalMediaCMS['features']['sideBar']>
|
||||||
|
): MediaCMSConfig['sidebar'] => ({
|
||||||
|
hideHomeLink: settings?.hideHomeLink === true,
|
||||||
|
hideTagsLink: settings?.hideTagsLink === true,
|
||||||
|
hideCategoriesLink: settings?.hideCategoriesLink === true,
|
||||||
|
});
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
let SITE = null;
|
|
||||||
|
|
||||||
export function init(settings) {
|
|
||||||
SITE = {
|
|
||||||
id: 'media-cms',
|
|
||||||
url: '',
|
|
||||||
api: '',
|
|
||||||
title: '',
|
|
||||||
useRoundedCorners: true,
|
|
||||||
version: '1.0.0',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== settings) {
|
|
||||||
if ('string' === typeof settings.id) {
|
|
||||||
SITE.id = settings.id.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof settings.url) {
|
|
||||||
SITE.url = settings.url.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof settings.api) {
|
|
||||||
SITE.api = settings.api.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof settings.title) {
|
|
||||||
SITE.title = settings.title.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('boolean' === typeof settings.useRoundedCorners) {
|
|
||||||
SITE.useRoundedCorners = settings.useRoundedCorners;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof settings.version) {
|
|
||||||
SITE.version = settings.version.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return SITE;
|
|
||||||
}
|
|
||||||
10
frontend/src/static/js/utils/settings/site.ts
Executable file
10
frontend/src/static/js/utils/settings/site.ts
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export const siteConfig = (settings?: DeepPartial<GlobalMediaCMS['site']>): MediaCMSConfig['site'] => ({
|
||||||
|
id: settings?.id?.trim() ?? 'media-cms',
|
||||||
|
url: settings?.url?.trim() ?? '',
|
||||||
|
api: settings?.api?.trim() ?? '',
|
||||||
|
title: settings?.title?.trim() ?? '',
|
||||||
|
useRoundedCorners: settings?.useRoundedCorners === false ? false : true,
|
||||||
|
version: settings?.version?.trim() ?? '1.0.0', // @todo: Validate version format
|
||||||
|
});
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
let TAXONOMIES = null;
|
|
||||||
|
|
||||||
export function init(settings) {
|
|
||||||
TAXONOMIES = {
|
|
||||||
tags: {
|
|
||||||
enabled: false,
|
|
||||||
title: 'Tags',
|
|
||||||
},
|
|
||||||
categories: {
|
|
||||||
enabled: false,
|
|
||||||
title: 'Categories',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== settings) {
|
|
||||||
for (let k in TAXONOMIES) {
|
|
||||||
if (void 0 !== settings[k]) {
|
|
||||||
TAXONOMIES[k].enabled = true;
|
|
||||||
|
|
||||||
if (void 0 !== settings[k].enabled && false === settings[k].enabled) {
|
|
||||||
TAXONOMIES[k].enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof settings[k].title) {
|
|
||||||
TAXONOMIES[k].title = settings[k].title.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return TAXONOMIES;
|
|
||||||
}
|
|
||||||
25
frontend/src/static/js/utils/settings/taxonomies.ts
Executable file
25
frontend/src/static/js/utils/settings/taxonomies.ts
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export function taxonomiesConfig(settings?: DeepPartial<GlobalMediaCMS['site']['taxonomies']>) {
|
||||||
|
const ret: MediaCMSConfig['enabled']['taxonomies'] = {
|
||||||
|
tags: { enabled: false, title: 'Tags' },
|
||||||
|
categories: { enabled: false, title: 'Categories' },
|
||||||
|
};
|
||||||
|
|
||||||
|
// @todo: Similar code in 'pages.ts'
|
||||||
|
for (let sk in settings) {
|
||||||
|
const key = sk as keyof typeof settings;
|
||||||
|
|
||||||
|
if (!ret[key]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[key].enabled = settings[key]?.enabled === false ? false : true; // @todo: Check this again
|
||||||
|
|
||||||
|
if (settings[key]?.title !== undefined) {
|
||||||
|
ret[key].title = settings[key].title.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
let THEME = null;
|
|
||||||
|
|
||||||
export function init(theme, logo) {
|
|
||||||
THEME = {
|
|
||||||
mode: 'light', // Valid options: 'light', 'dark'.
|
|
||||||
switch: {
|
|
||||||
enabled: true,
|
|
||||||
position: 'header', // Valid options: 'header', 'sidebar'.
|
|
||||||
},
|
|
||||||
logo: {
|
|
||||||
lightMode: {
|
|
||||||
img: '',
|
|
||||||
svg: '',
|
|
||||||
},
|
|
||||||
darkMode: {
|
|
||||||
img: '',
|
|
||||||
svg: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (void 0 !== theme) {
|
|
||||||
if ('string' === typeof theme.mode) {
|
|
||||||
THEME.mode = theme.mode.trim();
|
|
||||||
THEME.mode = 'dark' === THEME.mode ? 'dark' : 'light';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== theme.switch) {
|
|
||||||
if (false === theme.switch.enabled) {
|
|
||||||
THEME.switch.enabled = theme.switch.enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof theme.switch.position) {
|
|
||||||
THEME.switch.position = theme.switch.position.trim();
|
|
||||||
THEME.switch.position = 'sidebar' === theme.switch.position ? 'sidebar' : 'header';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== logo) {
|
|
||||||
if (void 0 !== logo.lightMode) {
|
|
||||||
if ('string' === typeof logo.lightMode.img) {
|
|
||||||
THEME.logo.lightMode.img = logo.lightMode.img.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof logo.lightMode.svg) {
|
|
||||||
THEME.logo.lightMode.svg = logo.lightMode.svg.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (void 0 !== logo.darkMode) {
|
|
||||||
if ('string' === typeof logo.darkMode.img) {
|
|
||||||
THEME.logo.darkMode.img = logo.darkMode.img.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('string' === typeof logo.darkMode.svg) {
|
|
||||||
THEME.logo.darkMode.svg = logo.darkMode.svg.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function settings() {
|
|
||||||
return THEME;
|
|
||||||
}
|
|
||||||
51
frontend/src/static/js/utils/settings/theme.ts
Executable file
51
frontend/src/static/js/utils/settings/theme.ts
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
import { DeepPartial, GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export function themeConfig(
|
||||||
|
theme?: DeepPartial<GlobalMediaCMS['site']['theme']>,
|
||||||
|
logo?: DeepPartial<GlobalMediaCMS['site']['logo']>
|
||||||
|
) {
|
||||||
|
const ret: MediaCMSConfig['theme'] = {
|
||||||
|
mode: 'light',
|
||||||
|
switch: { enabled: true, position: 'header' },
|
||||||
|
logo: { lightMode: { img: '', svg: '' }, darkMode: { img: '', svg: '' } },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (theme) {
|
||||||
|
if (theme.mode?.trim() === 'dark') {
|
||||||
|
ret.mode = 'dark';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theme.switch) {
|
||||||
|
if (theme.switch.enabled === false) {
|
||||||
|
ret.switch.enabled = false;
|
||||||
|
}
|
||||||
|
if (theme.switch.position?.trim() === 'sidebar') {
|
||||||
|
ret.switch.position = 'sidebar';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logo) {
|
||||||
|
if (logo.lightMode) {
|
||||||
|
if (logo.lightMode.img) {
|
||||||
|
ret.logo.lightMode.img = logo.lightMode.img.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logo.lightMode.svg) {
|
||||||
|
ret.logo.lightMode.svg = logo.lightMode.svg.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logo.darkMode) {
|
||||||
|
if (logo.darkMode?.img) {
|
||||||
|
ret.logo.darkMode.img = logo.darkMode.img.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logo.darkMode?.svg) {
|
||||||
|
ret.logo.darkMode.svg = logo.darkMode.svg.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
let PAGES = null;
|
|
||||||
|
|
||||||
export function init(pages_url) {
|
|
||||||
PAGES = {};
|
|
||||||
|
|
||||||
for (let k in pages_url) {
|
|
||||||
PAGES[k] = pages_url[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pages() {
|
|
||||||
return PAGES;
|
|
||||||
}
|
|
||||||
59
frontend/src/static/js/utils/settings/url.ts
Executable file
59
frontend/src/static/js/utils/settings/url.ts
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
import { GlobalMediaCMS, MediaCMSConfig } from '../../types';
|
||||||
|
|
||||||
|
export const urlConfig = ({
|
||||||
|
profileId,
|
||||||
|
site,
|
||||||
|
url,
|
||||||
|
user,
|
||||||
|
}: Pick<GlobalMediaCMS, 'profileId' | 'site' | 'url' | 'user'>): MediaCMSConfig['url'] => ({
|
||||||
|
home: url.home,
|
||||||
|
admin: !user.is.anonymous && user.is.admin ? url.admin : '',
|
||||||
|
error404: url.error404,
|
||||||
|
embed: site.url.replace(/\/+$/, '') + '/embed?m=',
|
||||||
|
latest: url.latestMedia,
|
||||||
|
featured: url.featuredMedia,
|
||||||
|
recommended: url.recommendedMedia,
|
||||||
|
signin: url.signin,
|
||||||
|
signout: !user.is.anonymous ? url.signout : '',
|
||||||
|
register: url.register,
|
||||||
|
changePassword: !user.is.anonymous ? url.changePassword : '',
|
||||||
|
members: url.members,
|
||||||
|
search: {
|
||||||
|
base: url.search,
|
||||||
|
query: url.search + '?q=',
|
||||||
|
tag: url.search + '?t=',
|
||||||
|
category: url.search + '?c=',
|
||||||
|
},
|
||||||
|
profile:
|
||||||
|
site.devEnv === true
|
||||||
|
? {
|
||||||
|
media: user.pages.media,
|
||||||
|
about: user.pages.about,
|
||||||
|
playlists: user.pages.playlists,
|
||||||
|
shared_by_me: user.pages.media + '/shared_by_me',
|
||||||
|
shared_with_me: user.pages.media + '/shared_with_me',
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
media: site.url.replace(/\/$/, '') + '/user/' + profileId,
|
||||||
|
about: site.url.replace(/\/$/, '') + '/user/' + profileId + '/about',
|
||||||
|
playlists: site.url.replace(/\/$/, '') + '/user/' + profileId + '/playlists',
|
||||||
|
shared_by_me: site.url.replace(/\/$/, '') + '/user/' + profileId + '/shared_by_me',
|
||||||
|
shared_with_me: site.url.replace(/\/$/, '') + '/user/' + profileId + '/shared_with_me',
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
liked: url.likedMedia,
|
||||||
|
history: url.history,
|
||||||
|
addMedia: url.addMedia,
|
||||||
|
editChannel: url.editChannel,
|
||||||
|
editProfile: url.editProfile,
|
||||||
|
},
|
||||||
|
archive: {
|
||||||
|
tags: url.tags,
|
||||||
|
categories: url.categories,
|
||||||
|
},
|
||||||
|
manage: {
|
||||||
|
media: !user.is.anonymous ? url.manageMedia : '',
|
||||||
|
users: !user.is.anonymous ? url.manageUsers : '',
|
||||||
|
comments: !user.is.anonymous ? url.manageComments : '',
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,46 +1,40 @@
|
|||||||
import { init, endpoints } from '../../../src/static/js/utils/settings/api';
|
import { apiConfig } from '../../../src/static/js/utils/settings/api';
|
||||||
|
|
||||||
const apiConfig = (url: any, ep: any) => {
|
|
||||||
init(url, ep);
|
|
||||||
return endpoints();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
|
||||||
describe('api', () => {
|
|
||||||
const sampleGlobal = {
|
const sampleGlobal = {
|
||||||
site: { api: 'https://example.com/api/v1///' },
|
site: { api: 'https://example.com/api///' },
|
||||||
// The endpoints below intentionally contain leading slashes to ensure they are stripped
|
// endpoints below intentionally contain leading slashes to ensure they are stripped
|
||||||
api: {
|
api: {
|
||||||
media: '/media/',
|
media: '/v1/media/',
|
||||||
members: '/users//',
|
playlists: '/v1/playlists',
|
||||||
playlists: '/playlists',
|
members: '/v1/users',
|
||||||
liked: '/user/liked',
|
liked: '/v1/user/liked',
|
||||||
history: '/user/history',
|
history: '/v1/user/history',
|
||||||
tags: '/tags',
|
tags: '/v1/tags',
|
||||||
categories: '/categories',
|
categories: '/v1/categories',
|
||||||
manage_media: '/manage/media',
|
manage_media: '/v1/manage/media',
|
||||||
manage_users: '/manage/users',
|
manage_users: '/v1/manage/users',
|
||||||
manage_comments: '/manage/comments',
|
manage_comments: '/v1/manage/comments',
|
||||||
search: '/search',
|
search: '/v1/search',
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
test('Trims trailing slashes on base and ensures single slash joins', () => {
|
describe('utils/settings', () => {
|
||||||
const cfg = apiConfig(sampleGlobal.site.api, sampleGlobal.api);
|
describe('api', () => {
|
||||||
// @todo: Check again the cases of trailing slashes
|
test('trims trailing slashes on base and ensures single slash joins', () => {
|
||||||
|
const cfg = apiConfig(sampleGlobal.site.api as any, sampleGlobal.api as any);
|
||||||
expect(cfg.media).toBe('https://example.com/api/v1/media/');
|
expect(cfg.media).toBe('https://example.com/api/v1/media/');
|
||||||
expect(cfg.users).toBe('https://example.com/api/v1/users//');
|
// base should not end with a slash and endpoint leading slash stripped
|
||||||
|
expect(cfg.users).toBe('https://example.com/api/v1/users');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Adds featured/recommended query to media variants', () => {
|
test('adds featured/recommended query to media variants', () => {
|
||||||
const cfg = apiConfig(sampleGlobal.site.api, sampleGlobal.api);
|
const cfg = apiConfig(sampleGlobal.site.api as any, sampleGlobal.api as any);
|
||||||
expect(cfg.featured).toBe('https://example.com/api/v1/media/?show=featured');
|
expect(cfg.featured).toBe('https://example.com/api/v1/media/?show=featured');
|
||||||
expect(cfg.recommended).toBe('https://example.com/api/v1/media/?show=recommended');
|
expect(cfg.recommended).toBe('https://example.com/api/v1/media/?show=recommended');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Builds nested user, archive, manage maps', () => {
|
test('builds nested user, archive, manage maps', () => {
|
||||||
const cfg = apiConfig(sampleGlobal.site.api, sampleGlobal.api);
|
const cfg = apiConfig(sampleGlobal.site.api as any, sampleGlobal.api as any);
|
||||||
|
|
||||||
expect(cfg.user.liked).toBe('https://example.com/api/v1/user/liked');
|
expect(cfg.user.liked).toBe('https://example.com/api/v1/user/liked');
|
||||||
expect(cfg.user.history).toBe('https://example.com/api/v1/user/history');
|
expect(cfg.user.history).toBe('https://example.com/api/v1/user/history');
|
||||||
expect(cfg.user.playlists).toBe('https://example.com/api/v1/playlists?author=');
|
expect(cfg.user.playlists).toBe('https://example.com/api/v1/playlists?author=');
|
||||||
@@ -53,22 +47,30 @@ describe('utils/settings', () => {
|
|||||||
expect(cfg.manage.comments).toBe('https://example.com/api/v1/manage/comments');
|
expect(cfg.manage.comments).toBe('https://example.com/api/v1/manage/comments');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Builds search endpoints with expected query fragments', () => {
|
test('builds search endpoints with expected query fragments', () => {
|
||||||
const cfg = apiConfig(sampleGlobal.site.api, sampleGlobal.api);
|
const cfg = apiConfig(sampleGlobal.site.api as any, sampleGlobal.api as any);
|
||||||
expect(cfg.search.query).toBe('https://example.com/api/v1/search?q=');
|
expect(cfg.search.query).toBe('https://example.com/api/v1/search?q=');
|
||||||
expect(cfg.search.titles).toBe('https://example.com/api/v1/search?show=titles&q=');
|
expect(cfg.search.titles).toBe('https://example.com/api/v1/search?show=titles&q=');
|
||||||
expect(cfg.search.tag).toBe('https://example.com/api/v1/search?t=');
|
expect(cfg.search.tag).toBe('https://example.com/api/v1/search?t=');
|
||||||
expect(cfg.search.category).toBe('https://example.com/api/v1/search?c=');
|
expect(cfg.search.category).toBe('https://example.com/api/v1/search?c=');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Handles base url with path and endpoint with existing query', () => {
|
test('handles base url with path and endpoint with existing query', () => {
|
||||||
const cfg = apiConfig('https://example.com/base/', {
|
const base = 'https://example.com/base/';
|
||||||
|
const endpoints = {
|
||||||
media: 'items?x=1',
|
media: 'items?x=1',
|
||||||
playlists: '/pls/',
|
playlists: '/pls/',
|
||||||
|
members: 'users',
|
||||||
liked: 'me/liked',
|
liked: 'me/liked',
|
||||||
|
history: 'me/history',
|
||||||
|
tags: 't',
|
||||||
categories: '/c',
|
categories: '/c',
|
||||||
|
manage_media: 'm/media',
|
||||||
|
manage_users: 'm/users',
|
||||||
|
manage_comments: 'm/comments',
|
||||||
search: '/s',
|
search: '/s',
|
||||||
});
|
} as any;
|
||||||
|
const cfg = apiConfig(base as any, endpoints);
|
||||||
expect(cfg.media).toBe('https://example.com/base/items?x=1');
|
expect(cfg.media).toBe('https://example.com/base/items?x=1');
|
||||||
expect(cfg.playlists).toBe('https://example.com/base/pls/');
|
expect(cfg.playlists).toBe('https://example.com/base/pls/');
|
||||||
expect(cfg.user.liked).toBe('https://example.com/base/me/liked');
|
expect(cfg.user.liked).toBe('https://example.com/base/me/liked');
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { config } from '../../../src/static/js/utils/settings/config';
|
import { config } from '../../../src/static/js/utils/settings/config';
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
// The aggregator pulls all sub-configs together. We validate composition and memoization.
|
||||||
describe('config', () => {
|
// Behaviors to test:
|
||||||
|
// 1) Builds enabled pages by merging site.pages and site.userPages and passes to optionsPages
|
||||||
|
// 2) Produces api endpoints derived from site.api + api endpoints
|
||||||
|
// 3) Honors user/feature flags within member capabilities and url manage links visibility
|
||||||
|
// 4) Applies theme and logo mapping and site defaults when missing
|
||||||
|
// 5) Memoizes result and returns same object instance on subsequent calls
|
||||||
|
|
||||||
|
// @todo: Replace 'baseGlobal' with 'sampleGlobalMediaCMS' and add missing properties value checks.
|
||||||
const baseGlobal = {
|
const baseGlobal = {
|
||||||
profileId: 'john',
|
profileId: 'john',
|
||||||
site: {
|
site: {
|
||||||
@@ -71,12 +78,7 @@ describe('utils/settings', () => {
|
|||||||
},
|
},
|
||||||
contents: {
|
contents: {
|
||||||
notifications: {
|
notifications: {
|
||||||
messages: {
|
messages: { addToLiked: 'Yay', removeFromLiked: 'Oops', addToDisliked: 'nay', removeFromDisliked: 'ok' },
|
||||||
addToLiked: 'Yay',
|
|
||||||
removeFromLiked: 'Oops',
|
|
||||||
addToDisliked: 'nay',
|
|
||||||
removeFromDisliked: 'ok',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pages: {
|
pages: {
|
||||||
@@ -133,8 +135,10 @@ describe('utils/settings', () => {
|
|||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
describe('utils/settings', () => {
|
||||||
|
describe('config', () => {
|
||||||
test('merges enabled pages and passes titles into options.pages.home sections', () => {
|
test('merges enabled pages and passes titles into options.pages.home sections', () => {
|
||||||
const cfg = config(baseGlobal);
|
const cfg = config(baseGlobal as any);
|
||||||
expect(cfg.enabled.pages.latest).toStrictEqual({ enabled: true, title: 'Recent uploads' });
|
expect(cfg.enabled.pages.latest).toStrictEqual({ enabled: true, title: 'Recent uploads' });
|
||||||
expect(cfg.enabled.pages.featured).toStrictEqual({ enabled: true, title: 'Featured picks' });
|
expect(cfg.enabled.pages.featured).toStrictEqual({ enabled: true, title: 'Featured picks' });
|
||||||
expect(cfg.enabled.pages.recommended).toStrictEqual({ enabled: false, title: 'You may like' });
|
expect(cfg.enabled.pages.recommended).toStrictEqual({ enabled: false, title: 'You may like' });
|
||||||
@@ -144,14 +148,14 @@ describe('utils/settings', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('produces api endpoints based on site.api and api endpoints', () => {
|
test('produces api endpoints based on site.api and api endpoints', () => {
|
||||||
const cfg = config(baseGlobal);
|
const cfg = config(baseGlobal as any);
|
||||||
expect(cfg.api.media).toBe('https://example.com/api/v1/media/');
|
expect(cfg.api.media).toBe('https://example.com/api/v1/media/');
|
||||||
expect(cfg.api.user.liked).toBe('https://example.com/api/v1/user/liked');
|
expect(cfg.api.user.liked).toBe('https://example.com/api/v1/user/liked');
|
||||||
expect(cfg.api.search.query).toBe('https://example.com/api/v1/search?q=');
|
expect(cfg.api.search.query).toBe('https://example.com/api/v1/search?q=');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('member and url manage links reflect user and feature flags', () => {
|
test('member and url manage links reflect user and feature flags', () => {
|
||||||
const cfg = config(baseGlobal);
|
const cfg = config(baseGlobal as any);
|
||||||
expect(cfg.member.is).toStrictEqual({ admin: true, anonymous: false });
|
expect(cfg.member.is).toStrictEqual({ admin: true, anonymous: false });
|
||||||
expect(cfg.member.can).toMatchObject({
|
expect(cfg.member.can).toMatchObject({
|
||||||
manageMedia: true,
|
manageMedia: true,
|
||||||
@@ -166,7 +170,7 @@ describe('utils/settings', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('theme and site defaults propagate correctly', () => {
|
test('theme and site defaults propagate correctly', () => {
|
||||||
const cfg = config(baseGlobal);
|
const cfg = config(baseGlobal as any);
|
||||||
expect(cfg.theme.mode).toBe('dark');
|
expect(cfg.theme.mode).toBe('dark');
|
||||||
expect(cfg.theme.switch.position).toBe('sidebar');
|
expect(cfg.theme.switch.position).toBe('sidebar');
|
||||||
expect(cfg.theme.logo.darkMode.img).toBe('/img/dark.png');
|
expect(cfg.theme.logo.darkMode.img).toBe('/img/dark.png');
|
||||||
@@ -175,13 +179,13 @@ describe('utils/settings', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('memoizes and returns the same object instance on repeated calls', () => {
|
test('memoizes and returns the same object instance on repeated calls', () => {
|
||||||
const first = config(baseGlobal);
|
const first = config(baseGlobal as any);
|
||||||
const second = config(baseGlobal);
|
const second = config(baseGlobal as any);
|
||||||
expect(second).toBe(first);
|
expect(second).toBe(first);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('url profile paths use site.url when not in dev env', () => {
|
test('url profile paths use site.url when not in dev env', () => {
|
||||||
const cfg = config(baseGlobal);
|
const cfg = config(baseGlobal as any);
|
||||||
expect(cfg.url.profile.media).toBe('https://example.com/user/john');
|
expect(cfg.url.profile.media).toBe('https://example.com/user/john');
|
||||||
expect(cfg.url.embed).toBe('https://example.com/embed?m=');
|
expect(cfg.url.embed).toBe('https://example.com/embed?m=');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/contents';
|
import { contentsConfig } from '../../../src/static/js/utils/settings/contents';
|
||||||
|
|
||||||
const contentsConfig = (obj: any) => {
|
|
||||||
init(obj);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('contents', () => {
|
describe('contents', () => {
|
||||||
@@ -53,8 +48,7 @@ describe('utils/settings', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// @todo: Revisit this behavior
|
test('Sidebar menu items require text, link, icon and get trimmed', () => {
|
||||||
test('Sidebar menu items require text, link, icon and NOT get trimmed', () => {
|
|
||||||
const cfg = contentsConfig({
|
const cfg = contentsConfig({
|
||||||
sidebar: {
|
sidebar: {
|
||||||
mainMenuExtraItems: [
|
mainMenuExtraItems: [
|
||||||
@@ -62,22 +56,63 @@ describe('utils/settings', () => {
|
|||||||
{ text: 'no-link', icon: 'i' },
|
{ text: 'no-link', icon: 'i' },
|
||||||
{ link: '/missing-text', icon: 'i' },
|
{ link: '/missing-text', icon: 'i' },
|
||||||
{ text: 'no-icon', link: '/x' },
|
{ text: 'no-icon', link: '/x' },
|
||||||
|
null as any,
|
||||||
|
undefined,
|
||||||
],
|
],
|
||||||
navMenuItems: [
|
navMenuItems: [
|
||||||
{ text: ' B ', link: ' /b ', icon: ' i-b ' },
|
{ text: ' B ', link: ' /b ', icon: ' i-b ' },
|
||||||
{ text: ' ', link: '/bad', icon: 'i' },
|
{ text: ' ', link: '/bad', icon: 'i' },
|
||||||
|
null as any,
|
||||||
|
undefined,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(cfg.sidebar.mainMenuExtra.items).toStrictEqual([
|
expect(cfg.sidebar.mainMenuExtra.items).toEqual([{ text: 'A', link: '/a', icon: 'i-a', className: 'cls' }]);
|
||||||
{ text: ' A ', link: ' /a ', icon: ' i-a ', className: ' cls ' },
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(cfg.sidebar.navMenu.items).toStrictEqual([
|
expect(cfg.sidebar.navMenu.items).toEqual([{ text: 'B', link: '/b', icon: 'i-b', className: '' }]);
|
||||||
{ text: ' B ', link: ' /b ', icon: ' i-b ', className: undefined },
|
});
|
||||||
{ text: ' ', link: '/bad', icon: 'i', className: undefined },
|
|
||||||
]);
|
test('sidebar strings are trimmed or default to empty', () => {
|
||||||
|
const cfg = contentsConfig({
|
||||||
|
sidebar: {
|
||||||
|
belowNavMenu: ' X ',
|
||||||
|
belowThemeSwitcher: ' Y ',
|
||||||
|
footer: ' Z ',
|
||||||
|
},
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
expect(cfg.sidebar.belowNavMenu).toBe('X');
|
||||||
|
expect(cfg.sidebar.belowThemeSwitcher).toBe('Y');
|
||||||
|
expect(cfg.sidebar.footer).toBe('Z');
|
||||||
|
|
||||||
|
const cfg2 = contentsConfig({ sidebar: {} } as any);
|
||||||
|
expect(cfg2.sidebar.belowNavMenu).toBe('');
|
||||||
|
expect(cfg2.sidebar.belowThemeSwitcher).toBe('');
|
||||||
|
expect(cfg2.sidebar.footer).toBe('');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('uploader strings are trimmed or default to empty', () => {
|
||||||
|
const cfg = contentsConfig({
|
||||||
|
uploader: { belowUploadArea: ' U1 ', postUploadMessage: ' U2 ' },
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
expect(cfg.uploader.belowUploadArea).toBe('U1');
|
||||||
|
expect(cfg.uploader.postUploadMessage).toBe('U2');
|
||||||
|
|
||||||
|
const cfg2 = contentsConfig({ uploader: {} } as any);
|
||||||
|
expect(cfg2.uploader.belowUploadArea).toBe('');
|
||||||
|
expect(cfg2.uploader.postUploadMessage).toBe('');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('handles completely missing settings by returning defaults', () => {
|
||||||
|
const cfg = contentsConfig(undefined as any);
|
||||||
|
expect(cfg.header.right).toBe('');
|
||||||
|
expect(cfg.header.onLogoRight).toBe('');
|
||||||
|
expect(cfg.sidebar.mainMenuExtra.items).toEqual([]);
|
||||||
|
expect(cfg.sidebar.navMenu.items).toEqual([]);
|
||||||
|
expect(cfg.sidebar.footer).toBe('');
|
||||||
|
expect(cfg.uploader.postUploadMessage).toBe('');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/media';
|
import { mediaConfig } from '../../../src/static/js/utils/settings/media';
|
||||||
|
|
||||||
const mediaConfig = (item?: any, shareOptions?: any) => {
|
|
||||||
init(item, shareOptions);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('media', () => {
|
describe('media', () => {
|
||||||
@@ -27,14 +22,17 @@ describe('utils/settings', () => {
|
|||||||
expect(cfg.share.options).toEqual([]);
|
expect(cfg.share.options).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// @todo: Revisit this behavior
|
|
||||||
test('Filters share options to valid ones and trims whitespace', () => {
|
test('Filters share options to valid ones and trims whitespace', () => {
|
||||||
const cfg = mediaConfig(undefined, [' embed ', 'email', ' email ']);
|
const cfg = mediaConfig(undefined, [' embed ', 'email', ' email '] as unknown as Array<
|
||||||
expect(cfg.share.options).toEqual(['email']);
|
'embed' | 'email' | undefined
|
||||||
|
>);
|
||||||
|
expect(cfg.share.options).toEqual(['embed', 'email', 'email']); // @todo: Revisit this.
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Ignores falsy and invalid share options', () => {
|
test('Ignores falsy and invalid share options', () => {
|
||||||
const cfg = mediaConfig(undefined, [undefined, '', ' ', 'invalid', 'share', 'EMBED']);
|
const cfg = mediaConfig(undefined, [undefined, '', ' ', 'invalid', 'share', 'EMBED'] as unknown as Array<
|
||||||
|
'embed' | 'email' | undefined
|
||||||
|
>);
|
||||||
expect(cfg.share.options).toEqual([]);
|
expect(cfg.share.options).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/member';
|
import { memberConfig } from '../../../src/static/js/utils/settings/member';
|
||||||
|
|
||||||
const memberConfig = (user?: any, features?: any) => {
|
|
||||||
init(user, features);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('member', () => {
|
describe('member', () => {
|
||||||
@@ -56,8 +51,8 @@ describe('utils/settings', () => {
|
|||||||
can: {
|
can: {
|
||||||
changePassword: true,
|
changePassword: true,
|
||||||
deleteProfile: true,
|
deleteProfile: true,
|
||||||
addComment: true,
|
addComment: false,
|
||||||
mentionComment: true,
|
mentionComment: false,
|
||||||
deleteComment: true,
|
deleteComment: true,
|
||||||
editMedia: true,
|
editMedia: true,
|
||||||
deleteMedia: true,
|
deleteMedia: true,
|
||||||
@@ -90,8 +85,8 @@ describe('utils/settings', () => {
|
|||||||
changePassword: true,
|
changePassword: true,
|
||||||
deleteProfile: true,
|
deleteProfile: true,
|
||||||
readComment: true,
|
readComment: true,
|
||||||
addComment: true,
|
addComment: false,
|
||||||
mentionComment: true,
|
mentionComment: false,
|
||||||
deleteComment: true,
|
deleteComment: true,
|
||||||
editMedia: true,
|
editMedia: true,
|
||||||
deleteMedia: true,
|
deleteMedia: true,
|
||||||
@@ -127,6 +122,12 @@ describe('utils/settings', () => {
|
|||||||
expect(cfg2.can.mentionComment).toBe(true);
|
expect(cfg2.can.mentionComment).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Preserves comment capabilities from user.can when media.actions is missing', () => {
|
||||||
|
const cfg = memberConfig({ is: { anonymous: false }, can: { addComment: true, mentionComment: true } });
|
||||||
|
expect(cfg.can.addComment).toBe(true);
|
||||||
|
expect(cfg.can.mentionComment).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
test('Header login/register reflect headerBar feature flags', () => {
|
test('Header login/register reflect headerBar feature flags', () => {
|
||||||
expect(memberConfig(undefined, { headerBar: { hideLogin: true } }).can.login).toBe(false);
|
expect(memberConfig(undefined, { headerBar: { hideLogin: true } }).can.login).toBe(false);
|
||||||
expect(memberConfig(undefined, { headerBar: { hideRegister: true } }).can.register).toBe(false);
|
expect(memberConfig(undefined, { headerBar: { hideRegister: true } }).can.register).toBe(false);
|
||||||
@@ -149,6 +150,16 @@ describe('utils/settings', () => {
|
|||||||
expect(cfg1.can.saveMedia).toBe(true);
|
expect(cfg1.can.saveMedia).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Applies legacy defaults when media.actions exists but fields are missing', () => {
|
||||||
|
const cfg = memberConfig(undefined, { media: { actions: {} } });
|
||||||
|
expect(cfg.can.likeMedia).toBe(true);
|
||||||
|
expect(cfg.can.dislikeMedia).toBe(true);
|
||||||
|
expect(cfg.can.reportMedia).toBe(true);
|
||||||
|
expect(cfg.can.downloadMedia).toBe(false);
|
||||||
|
expect(cfg.can.saveMedia).toBe(false);
|
||||||
|
expect(cfg.can.shareMedia).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
test('User flags canSeeMembersPage/usersNeedsToBeApproved/readComment default handling', () => {
|
test('User flags canSeeMembersPage/usersNeedsToBeApproved/readComment default handling', () => {
|
||||||
const cfg1 = memberConfig({
|
const cfg1 = memberConfig({
|
||||||
is: { anonymous: false },
|
is: { anonymous: false },
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/notifications';
|
import { notificationsConfig } from '../../../src/static/js/utils/settings/notifications';
|
||||||
|
|
||||||
const notificationsConfig = (sett?: any) => {
|
|
||||||
init(sett);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('notifications', () => {
|
describe('notifications', () => {
|
||||||
@@ -19,8 +14,7 @@ describe('utils/settings', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// @todo: Revisit this behavior
|
test('Trims incoming message values and applies only when non-empty', () => {
|
||||||
test('Keep incoming message values without processing', () => {
|
|
||||||
const cfg = notificationsConfig({
|
const cfg = notificationsConfig({
|
||||||
messages: {
|
messages: {
|
||||||
addToLiked: ' Yay ',
|
addToLiked: ' Yay ',
|
||||||
@@ -30,17 +24,18 @@ describe('utils/settings', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(cfg.messages.addToLiked).toBe('Yay');
|
expect(cfg.messages.addToLiked).toBe('Yay');
|
||||||
expect(cfg.messages.removeFromLiked).toBe(' ');
|
// empty after trim -> keep default
|
||||||
expect(cfg.messages.addToDisliked).toBe('\nNope');
|
expect(cfg.messages.removeFromLiked).toBe('Removed from liked media');
|
||||||
expect(cfg.messages.removeFromDisliked).toBe('\t OK\t');
|
expect(cfg.messages.addToDisliked).toBe('Nope');
|
||||||
|
expect(cfg.messages.removeFromDisliked).toBe('OK');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Ignores undefined, keeping defaults', () => {
|
test('Ignores undefined or empty-string overrides, keeping defaults', () => {
|
||||||
const cfg = notificationsConfig({
|
const cfg = notificationsConfig({
|
||||||
messages: {
|
messages: {
|
||||||
addToLiked: undefined,
|
addToLiked: undefined,
|
||||||
removeFromLiked: undefined,
|
removeFromLiked: '',
|
||||||
addToDisliked: undefined,
|
addToDisliked: ' ',
|
||||||
removeFromDisliked: undefined,
|
removeFromDisliked: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -59,9 +54,18 @@ describe('utils/settings', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Handles extraneous keys by passing them through while keeping known defaults intact', () => {
|
test('Handles extraneous keys by passing them through while keeping known defaults intact', () => {
|
||||||
const cfg = notificationsConfig({ messages: { addToLiked: 'A', notARealKey: 'x' } });
|
const cfg = notificationsConfig({
|
||||||
expect(cfg.messages.notARealKey).toBeUndefined();
|
messages: {
|
||||||
|
addToLiked: 'A',
|
||||||
|
// Inject an unknown key; current implementation passes unknown keys through
|
||||||
|
...{ notARealKey: 'x' },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
expect(cfg.messages.addToLiked).toBe('A');
|
expect(cfg.messages.addToLiked).toBe('A');
|
||||||
|
// extraneous key currently copied over
|
||||||
|
expect((cfg.messages as any).notARealKey).toBe('x');
|
||||||
|
// sanity check known defaults remain for untouched keys
|
||||||
expect(cfg.messages.removeFromLiked).toBe('Removed from liked media');
|
expect(cfg.messages.removeFromLiked).toBe('Removed from liked media');
|
||||||
expect(cfg.messages.addToDisliked).toBe('Added to disliked media');
|
expect(cfg.messages.addToDisliked).toBe('Added to disliked media');
|
||||||
expect(cfg.messages.removeFromDisliked).toBe('Removed from disliked media');
|
expect(cfg.messages.removeFromDisliked).toBe('Removed from disliked media');
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/optionsEmbedded';
|
import { optionsEmbeddedConfig } from '../../../src/static/js/utils/settings/optionsEmbedded';
|
||||||
|
|
||||||
const optionsEmbeddedConfig = (embeddedVideo?: any) => {
|
|
||||||
init(embeddedVideo);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('optionsEmbedded', () => {
|
describe('optionsEmbedded', () => {
|
||||||
@@ -22,32 +17,30 @@ describe('utils/settings', () => {
|
|||||||
expect(cfg.video.dimensions).toStrictEqual({ width: 640, widthUnit: 'px', height: 360, heightUnit: 'px' });
|
expect(cfg.video.dimensions).toStrictEqual({ width: 640, widthUnit: 'px', height: 360, heightUnit: 'px' });
|
||||||
});
|
});
|
||||||
|
|
||||||
// @todo: Revisit this behavior
|
|
||||||
test('Ignores NaN and non-numeric width/height and keeps defaults', () => {
|
test('Ignores NaN and non-numeric width/height and keeps defaults', () => {
|
||||||
const cfg1 = optionsEmbeddedConfig({ initialDimensions: { width: NaN, height: NaN } });
|
const cfg1 = optionsEmbeddedConfig({ initialDimensions: { width: NaN, height: NaN } } as any);
|
||||||
expect(cfg1.video.dimensions).toStrictEqual({ width: 560, widthUnit: 'px', height: 315, heightUnit: 'px' });
|
expect(cfg1.video.dimensions).toStrictEqual({ width: 560, widthUnit: 'px', height: 315, heightUnit: 'px' });
|
||||||
|
|
||||||
const cfg2 = optionsEmbeddedConfig({ initialDimensions: { width: '640', height: '360' } });
|
const cfg2 = optionsEmbeddedConfig({ initialDimensions: { width: '640', height: '360' } } as any);
|
||||||
expect(cfg2.video.dimensions).toStrictEqual({
|
expect(cfg2.video.dimensions).toStrictEqual({ width: 560, widthUnit: 'px', height: 315, heightUnit: 'px' });
|
||||||
width: '640',
|
|
||||||
widthUnit: 'px',
|
|
||||||
height: '360',
|
|
||||||
heightUnit: 'px',
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// @todo: Revisit this behavior
|
|
||||||
test('Ignores provided widthUnit/heightUnit as they are not used', () => {
|
test('Ignores provided widthUnit/heightUnit as they are not used', () => {
|
||||||
const cfg = optionsEmbeddedConfig({
|
const cfg = optionsEmbeddedConfig({
|
||||||
initialDimensions: { width: 800, height: 450, widthUnit: 'percent', heightUnit: 'percent' },
|
initialDimensions: {
|
||||||
});
|
width: 800,
|
||||||
|
height: 450,
|
||||||
|
widthUnit: 'percent',
|
||||||
|
heightUnit: 'percent',
|
||||||
|
},
|
||||||
|
} as any);
|
||||||
|
// units should remain default 'px'
|
||||||
expect(cfg.video.dimensions.width).toBe(800);
|
expect(cfg.video.dimensions.width).toBe(800);
|
||||||
expect(cfg.video.dimensions.height).toBe(450);
|
expect(cfg.video.dimensions.height).toBe(450);
|
||||||
expect(cfg.video.dimensions.widthUnit).toBe('px');
|
expect(cfg.video.dimensions.widthUnit).toBe('px');
|
||||||
expect(cfg.video.dimensions.heightUnit).toBe('px');
|
expect(cfg.video.dimensions.heightUnit).toBe('px');
|
||||||
});
|
});
|
||||||
|
|
||||||
// @todo: Revisit this behavior
|
|
||||||
test('Does not mutate the provided settings object', () => {
|
test('Does not mutate the provided settings object', () => {
|
||||||
const input = {
|
const input = {
|
||||||
initialDimensions: { width: 700, height: 400, widthUnit: 'percent', heightUnit: 'percent' },
|
initialDimensions: { width: 700, height: 400, widthUnit: 'percent', heightUnit: 'percent' },
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/optionsPages';
|
import { optionsPagesConfig } from '../../../src/static/js/utils/settings/optionsPages';
|
||||||
|
|
||||||
const optionsPagesConfig = (home?: any, search?: any, media?: any, profile?: any, VALID_PAGES?: any) => {
|
|
||||||
init(home, search, media, profile, VALID_PAGES);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('optionsPages', () => {
|
describe('optionsPages', () => {
|
||||||
@@ -12,7 +7,8 @@ describe('utils/settings', () => {
|
|||||||
latest: { title: 'Recent' },
|
latest: { title: 'Recent' },
|
||||||
featured: { title: 'Spotlight' },
|
featured: { title: 'Spotlight' },
|
||||||
recommended: { title: 'You may like' },
|
recommended: { title: 'You may like' },
|
||||||
});
|
} as any);
|
||||||
|
|
||||||
expect(cfg.home.sections.latest.title).toBe('Recent');
|
expect(cfg.home.sections.latest.title).toBe('Recent');
|
||||||
expect(cfg.home.sections.featured.title).toBe('Spotlight');
|
expect(cfg.home.sections.featured.title).toBe('Spotlight');
|
||||||
expect(cfg.home.sections.recommended.title).toBe('You may like');
|
expect(cfg.home.sections.recommended.title).toBe('You may like');
|
||||||
@@ -26,86 +22,97 @@ describe('utils/settings', () => {
|
|||||||
recommended: { title: ' Recommended' },
|
recommended: { title: ' Recommended' },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(cfg.home.sections.latest.title).toBe('LATEST');
|
expect(cfg.home.sections.latest.title).toBe('LATEST');
|
||||||
expect(cfg.home.sections.featured.title).toBe('Featured');
|
expect(cfg.home.sections.featured.title).toBe('Featured');
|
||||||
expect(cfg.home.sections.recommended.title).toBe('Recommended');
|
expect(cfg.home.sections.recommended.title).toBe('Recommended');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Falls back to VALID_PAGES titles when custom home section titles are whitespace-only', () => {
|
||||||
|
const cfg = optionsPagesConfig(
|
||||||
|
{
|
||||||
|
sections: {
|
||||||
|
latest: { title: ' ' },
|
||||||
|
featured: { title: '\n\t' },
|
||||||
|
recommended: { title: ' ' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
latest: { title: 'Recent' },
|
||||||
|
featured: { title: 'Spotlight' },
|
||||||
|
recommended: { title: 'You may like' },
|
||||||
|
} as any
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(cfg.home.sections.latest.title).toBe('Recent');
|
||||||
|
expect(cfg.home.sections.featured.title).toBe('Spotlight');
|
||||||
|
expect(cfg.home.sections.recommended.title).toBe('You may like');
|
||||||
|
});
|
||||||
|
|
||||||
test('Sets search.advancedFilters true only when explicitly true', () => {
|
test('Sets search.advancedFilters true only when explicitly true', () => {
|
||||||
const def = optionsPagesConfig(undefined, undefined, undefined, undefined, {});
|
const def = optionsPagesConfig();
|
||||||
expect(def.search.advancedFilters).toBe(false);
|
expect(def.search.advancedFilters).toBe(false);
|
||||||
|
|
||||||
const falsy = optionsPagesConfig(undefined, { advancedFilters: false }, undefined, undefined, {});
|
const falsy = optionsPagesConfig(undefined, { advancedFilters: false } as any);
|
||||||
expect(falsy.search.advancedFilters).toBe(false);
|
expect(falsy.search.advancedFilters).toBe(false);
|
||||||
|
|
||||||
const truthy = optionsPagesConfig(undefined, { advancedFilters: true }, undefined, undefined, {});
|
const truthy = optionsPagesConfig(undefined, { advancedFilters: true } as any);
|
||||||
expect(truthy.search.advancedFilters).toBe(true);
|
expect(truthy.search.advancedFilters).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Configures media options with correct defaults and overrides', () => {
|
test('Configures media options with correct defaults and overrides', () => {
|
||||||
const def = optionsPagesConfig(undefined, undefined, undefined, undefined, {});
|
const def = optionsPagesConfig();
|
||||||
|
|
||||||
expect(def.media.categoriesWithTitle).toBe(false);
|
expect(def.media.categoriesWithTitle).toBe(false);
|
||||||
expect(def.media.htmlInDescription).toBe(false);
|
expect(def.media.htmlInDescription).toBe(false);
|
||||||
expect(def.media.displayViews).toBe(true);
|
expect(def.media.displayViews).toBe(true);
|
||||||
expect(def.media.related.initialSize).toBe(10);
|
expect(def.media.related.initialSize).toBe(10);
|
||||||
|
|
||||||
const override = optionsPagesConfig(
|
const override = optionsPagesConfig(undefined, undefined, {
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
{
|
|
||||||
categoriesWithTitle: true,
|
categoriesWithTitle: true,
|
||||||
htmlInDescription: true,
|
htmlInDescription: true,
|
||||||
hideViews: true,
|
hideViews: true,
|
||||||
related: { initialSize: 25 },
|
related: { initialSize: 25 },
|
||||||
},
|
});
|
||||||
undefined,
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(override.media.categoriesWithTitle).toBe(true);
|
expect(override.media.categoriesWithTitle).toBe(true);
|
||||||
expect(override.media.htmlInDescription).toBe(true);
|
expect(override.media.htmlInDescription).toBe(true);
|
||||||
expect(override.media.displayViews).toBe(false);
|
expect(override.media.displayViews).toBe(false);
|
||||||
expect(override.media.related.initialSize).toBe(10); // @todo: Fix this! It should return 25.
|
expect(override.media.related.initialSize).toBe(25);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Ignores NaN and non-numeric media.related.initialSize and keeps default 10', () => {
|
test('Ignores NaN and non-numeric media.related.initialSize and keeps default 10', () => {
|
||||||
const cfg1 = optionsPagesConfig(undefined, undefined, { related: { initialSize: NaN } }, undefined, {});
|
const cfg1 = optionsPagesConfig(undefined, undefined, { related: { initialSize: NaN } } as any);
|
||||||
expect(cfg1.media.related.initialSize).toBe(10);
|
expect(cfg1.media.related.initialSize).toBe(10);
|
||||||
|
|
||||||
const cfg2 = optionsPagesConfig(undefined, undefined, { related: { initialSize: '12' } }, undefined, {});
|
const cfg2 = optionsPagesConfig(undefined, undefined, { related: { initialSize: '12' as any } } as any);
|
||||||
expect(cfg2.media.related.initialSize).toBe(10);
|
expect(cfg2.media.related.initialSize).toBe(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Profile settings true only when explicitly true', () => {
|
test('Profile settings true only when explicitly true', () => {
|
||||||
const def = optionsPagesConfig(undefined, undefined, undefined, undefined, {});
|
const def = optionsPagesConfig();
|
||||||
expect(def.profile.htmlInDescription).toBe(false);
|
expect(def.profile.htmlInDescription).toBe(false);
|
||||||
expect(def.profile.includeHistory).toBe(false);
|
expect(def.profile.includeHistory).toBe(false);
|
||||||
expect(def.profile.includeLikedMedia).toBe(false);
|
expect(def.profile.includeLikedMedia).toBe(false);
|
||||||
|
|
||||||
const truthy = optionsPagesConfig(
|
const truthy = optionsPagesConfig(undefined, undefined, undefined, {
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
{
|
|
||||||
htmlInDescription: true,
|
htmlInDescription: true,
|
||||||
includeHistory: true,
|
includeHistory: true,
|
||||||
includeLikedMedia: true,
|
includeLikedMedia: true,
|
||||||
},
|
});
|
||||||
{}
|
|
||||||
);
|
|
||||||
expect(truthy.profile.htmlInDescription).toBe(true);
|
expect(truthy.profile.htmlInDescription).toBe(true);
|
||||||
expect(truthy.profile.includeHistory).toBe(true);
|
expect(truthy.profile.includeHistory).toBe(true);
|
||||||
expect(truthy.profile.includeLikedMedia).toBe(true);
|
expect(truthy.profile.includeLikedMedia).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// @todo: Revisit this behavior
|
|
||||||
test('Does not mutate provided input objects', () => {
|
test('Does not mutate provided input objects', () => {
|
||||||
const home = { sections: { latest: { title: ' A ' } } };
|
const home = { sections: { latest: { title: ' A ' } } };
|
||||||
const search = { advancedFilters: true };
|
const search = { advancedFilters: true };
|
||||||
const media = { hideViews: true, related: { initialSize: 5 } };
|
const media = { hideViews: true, related: { initialSize: 5 } };
|
||||||
const profile = { includeHistory: true };
|
const profile = { includeHistory: true };
|
||||||
const validPages = { latest: { title: 'L' }, featured: { title: 'F' }, recommended: { title: 'R' } };
|
const validPages: any = { latest: { title: 'L' }, featured: { title: 'F' }, recommended: { title: 'R' } };
|
||||||
|
|
||||||
const homeCopy = JSON.parse(JSON.stringify(home));
|
const homeCopy = JSON.parse(JSON.stringify(home));
|
||||||
const searchCopy = JSON.parse(JSON.stringify(search));
|
const searchCopy = JSON.parse(JSON.stringify(search));
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/pages';
|
import { pagesConfig } from '../../../src/static/js/utils/settings/pages';
|
||||||
|
|
||||||
const pagesConfig = (sett?: any) => {
|
|
||||||
init(sett);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('pages', () => {
|
describe('pages', () => {
|
||||||
@@ -25,9 +20,10 @@ describe('utils/settings', () => {
|
|||||||
featured: { enabled: true },
|
featured: { enabled: true },
|
||||||
recommended: { enabled: false },
|
recommended: { enabled: false },
|
||||||
members: { enabled: undefined },
|
members: { enabled: undefined },
|
||||||
liked: { enabled: null },
|
liked: { enabled: null as any },
|
||||||
history: { enabled: 0 },
|
history: { enabled: 0 as any },
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(cfg.latest.enabled).toBe(true);
|
expect(cfg.latest.enabled).toBe(true);
|
||||||
expect(cfg.featured.enabled).toBe(true);
|
expect(cfg.featured.enabled).toBe(true);
|
||||||
expect(cfg.recommended.enabled).toBe(false);
|
expect(cfg.recommended.enabled).toBe(false);
|
||||||
@@ -42,19 +38,28 @@ describe('utils/settings', () => {
|
|||||||
featured: { title: '\nFeatured' },
|
featured: { title: '\nFeatured' },
|
||||||
recommended: {},
|
recommended: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(cfg.latest.title).toBe('Latest');
|
expect(cfg.latest.title).toBe('Latest');
|
||||||
expect(cfg.featured.title).toBe('Featured');
|
expect(cfg.featured.title).toBe('Featured');
|
||||||
expect(cfg.recommended.title).toBe('Recommended');
|
expect(cfg.recommended.title).toBe('Recommended');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Ignores unknown keys in settings', () => {
|
test('Ignores unknown keys in settings', () => {
|
||||||
const cfg = pagesConfig({ unknownKey: { enabled: true, title: 'X' }, latest: { enabled: true } });
|
const cfg = pagesConfig({
|
||||||
|
// @ts-ignore
|
||||||
|
unknownKey: { enabled: true, title: 'X' },
|
||||||
|
latest: { enabled: true },
|
||||||
|
});
|
||||||
|
|
||||||
expect(cfg.latest.enabled).toBe(true);
|
expect(cfg.latest.enabled).toBe(true);
|
||||||
expect(cfg.unknownKey).toBeUndefined();
|
expect((cfg as any).unknownKey).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Does not mutate the input settings object', () => {
|
test('Does not mutate the input settings object', () => {
|
||||||
const input = { latest: { enabled: false, title: ' A ' }, featured: { enabled: true, title: ' B ' } };
|
const input = {
|
||||||
|
latest: { enabled: false, title: ' A ' },
|
||||||
|
featured: { enabled: true, title: ' B ' },
|
||||||
|
};
|
||||||
const snapshot = JSON.parse(JSON.stringify(input));
|
const snapshot = JSON.parse(JSON.stringify(input));
|
||||||
pagesConfig(input);
|
pagesConfig(input);
|
||||||
expect(input).toStrictEqual(snapshot);
|
expect(input).toStrictEqual(snapshot);
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/playlists';
|
import { playlistsConfig } from '../../../src/static/js/utils/settings/playlists';
|
||||||
|
|
||||||
const playlistsConfig = (plists?: any) => {
|
|
||||||
init(plists);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('playlists', () => {
|
describe('playlists', () => {
|
||||||
@@ -18,32 +13,33 @@ describe('utils/settings', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Includes only valid media types when both valid and invalid are provided', () => {
|
test('Includes only valid media types when both valid and invalid are provided', () => {
|
||||||
const cfg = playlistsConfig({ mediaTypes: ['audio', 'invalid', 'video', 'something'] });
|
const cfg = playlistsConfig({ mediaTypes: ['audio', 'invalid', 'video', 'something'] as any });
|
||||||
expect(cfg.mediaTypes).toEqual(['audio', 'video']);
|
expect(cfg.mediaTypes).toEqual(['audio', 'video']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Returns default when provided mediaTypes is non-array or undefined/null', () => {
|
test('Returns default when provided mediaTypes is non-array or undefined/null', () => {
|
||||||
expect(playlistsConfig({}).mediaTypes).toEqual(['audio', 'video']);
|
expect(playlistsConfig({} as any).mediaTypes).toEqual(['audio', 'video']);
|
||||||
expect(playlistsConfig({ mediaTypes: undefined }).mediaTypes).toEqual(['audio', 'video']);
|
expect(playlistsConfig({ mediaTypes: undefined } as any).mediaTypes).toEqual(['audio', 'video']);
|
||||||
// expect(playlistsConfig({ mediaTypes: null }).mediaTypes).toEqual(['audio', 'video']); // @todo: Revisit this behavior
|
expect(playlistsConfig({ mediaTypes: null as any }).mediaTypes).toEqual(['audio', 'video']);
|
||||||
expect(playlistsConfig({ mediaTypes: 'audio' }).mediaTypes).toEqual(['audio', 'video']);
|
expect(playlistsConfig({ mediaTypes: 'audio' as any }).mediaTypes).toEqual(['audio', 'video']);
|
||||||
expect(playlistsConfig({ mediaTypes: 123 }).mediaTypes).toEqual(['audio', 'video']);
|
expect(playlistsConfig({ mediaTypes: 123 as any }).mediaTypes).toEqual(['audio', 'video']);
|
||||||
});
|
});
|
||||||
|
|
||||||
// @todo: Revisit this behavior
|
|
||||||
test('Handles duplicates and preserves order among valid items', () => {
|
test('Handles duplicates and preserves order among valid items', () => {
|
||||||
const cfg = playlistsConfig({ mediaTypes: ['video', 'audio', 'video', 'audio', 'invalid'] });
|
const cfg = playlistsConfig({ mediaTypes: ['video', 'audio', 'video', 'audio', 'invalid'] as any });
|
||||||
|
// Implementation preserves order and includes duplicates; however, it later enforces default if empty only.
|
||||||
|
// Since duplicates are allowed by implementation, expect duplicates to be preserved.
|
||||||
expect(cfg.mediaTypes).toEqual(['video', 'audio', 'video', 'audio']);
|
expect(cfg.mediaTypes).toEqual(['video', 'audio', 'video', 'audio']);
|
||||||
});
|
});
|
||||||
|
|
||||||
// @todo: Revisit this behavior
|
|
||||||
test('Rejects non-exact case values (e.g., \"Audio\")', () => {
|
test('Rejects non-exact case values (e.g., \"Audio\")', () => {
|
||||||
const cfg = playlistsConfig({ mediaTypes: ['Audio', 'Video'] });
|
const cfg = playlistsConfig({ mediaTypes: ['Audio', 'Video'] as any });
|
||||||
|
// None match exactly, so default should apply.
|
||||||
expect(cfg.mediaTypes).toEqual(['audio', 'video']);
|
expect(cfg.mediaTypes).toEqual(['audio', 'video']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not mutate the input object', () => {
|
test('does not mutate the input object', () => {
|
||||||
const input = { mediaTypes: ['audio', 'video', 'invalid'] };
|
const input: any = { mediaTypes: ['audio', 'video', 'invalid'] };
|
||||||
const copy = JSON.parse(JSON.stringify(input));
|
const copy = JSON.parse(JSON.stringify(input));
|
||||||
playlistsConfig(input);
|
playlistsConfig(input);
|
||||||
expect(input).toEqual(copy);
|
expect(input).toEqual(copy);
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/sidebar';
|
import { sidebarConfig } from '../../../src/static/js/utils/settings/sidebar';
|
||||||
|
|
||||||
const sidebarConfig = (sett?: any) => {
|
|
||||||
init(sett);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('sidebar', () => {
|
describe('sidebar', () => {
|
||||||
@@ -32,14 +27,14 @@ describe('utils/settings', () => {
|
|||||||
// undefined
|
// undefined
|
||||||
expect(sidebarConfig({}).hideHomeLink).toBe(false);
|
expect(sidebarConfig({}).hideHomeLink).toBe(false);
|
||||||
// null
|
// null
|
||||||
expect(sidebarConfig({ hideTagsLink: null }).hideTagsLink).toBe(false);
|
expect(sidebarConfig({ hideTagsLink: null as any }).hideTagsLink).toBe(false);
|
||||||
// other types
|
// other types
|
||||||
expect(sidebarConfig({ hideCategoriesLink: 'yes' }).hideCategoriesLink).toBe(false);
|
expect(sidebarConfig({ hideCategoriesLink: 'yes' as any }).hideCategoriesLink).toBe(false);
|
||||||
expect(sidebarConfig({ hideCategoriesLink: 1 }).hideCategoriesLink).toBe(false);
|
expect(sidebarConfig({ hideCategoriesLink: 1 as any }).hideCategoriesLink).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Is resilient to partial inputs and ignores extra properties', () => {
|
test('Is resilient to partial inputs and ignores extra properties', () => {
|
||||||
const cfg = sidebarConfig({ hideTagsLink: true, extra: 'prop' });
|
const cfg = sidebarConfig({ hideTagsLink: true, extra: 'prop' } as any);
|
||||||
expect(cfg).toStrictEqual({ hideHomeLink: false, hideTagsLink: true, hideCategoriesLink: false });
|
expect(cfg).toStrictEqual({ hideHomeLink: false, hideTagsLink: true, hideCategoriesLink: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/site';
|
import { siteConfig } from '../../../src/static/js/utils/settings/site';
|
||||||
|
|
||||||
const siteConfig = (sett?: any) => {
|
|
||||||
init(sett);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('site', () => {
|
describe('site', () => {
|
||||||
@@ -27,6 +22,7 @@ describe('utils/settings', () => {
|
|||||||
title: ' Media CMS ',
|
title: ' Media CMS ',
|
||||||
version: ' 2.3.4 ',
|
version: ' 2.3.4 ',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(cfg).toStrictEqual({
|
expect(cfg).toStrictEqual({
|
||||||
id: 'my-site',
|
id: 'my-site',
|
||||||
url: 'https://example.com/',
|
url: 'https://example.com/',
|
||||||
@@ -42,22 +38,24 @@ describe('utils/settings', () => {
|
|||||||
expect(siteConfig({ useRoundedCorners: true }).useRoundedCorners).toBe(true);
|
expect(siteConfig({ useRoundedCorners: true }).useRoundedCorners).toBe(true);
|
||||||
expect(siteConfig({ useRoundedCorners: false }).useRoundedCorners).toBe(false);
|
expect(siteConfig({ useRoundedCorners: false }).useRoundedCorners).toBe(false);
|
||||||
// non-boolean should still evaluate to default true because only === false toggles it off
|
// non-boolean should still evaluate to default true because only === false toggles it off
|
||||||
expect(siteConfig({ useRoundedCorners: 'no' }).useRoundedCorners).toBe(true);
|
expect(siteConfig({ useRoundedCorners: 'no' as any }).useRoundedCorners).toBe(true);
|
||||||
expect(siteConfig({ useRoundedCorners: 0 }).useRoundedCorners).toBe(true);
|
expect(siteConfig({ useRoundedCorners: 0 as any }).useRoundedCorners).toBe(true);
|
||||||
expect(siteConfig({ useRoundedCorners: null }).useRoundedCorners).toBe(true);
|
expect(siteConfig({ useRoundedCorners: null as any }).useRoundedCorners).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Is resilient to partial inputs and ignores extra properties', () => {
|
test('Is resilient to partial inputs and ignores extra properties', () => {
|
||||||
const cfg = siteConfig({ id: ' x ', extra: 'y' });
|
const cfg = siteConfig({ id: ' x ', extra: 'y' } as any);
|
||||||
expect(cfg).toMatchObject({ id: 'x' });
|
expect(cfg).toMatchObject({ id: 'x' });
|
||||||
expect(Object.keys(cfg).sort()).toEqual(['api', 'id', 'title', 'url', 'useRoundedCorners', 'version']);
|
expect(Object.keys(cfg).sort()).toStrictEqual(
|
||||||
|
['api', 'id', 'title', 'url', 'useRoundedCorners', 'version'].sort()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Does not mutate input object', () => {
|
test('Does not mutate input object', () => {
|
||||||
const input = { id: ' my-id ', useRoundedCorners: false };
|
const input = { id: ' my-id ', useRoundedCorners: false };
|
||||||
const copy = JSON.parse(JSON.stringify(input));
|
const copy = JSON.parse(JSON.stringify(input));
|
||||||
siteConfig(input);
|
siteConfig(input);
|
||||||
expect(input).toEqual(copy);
|
expect(input).toStrictEqual(copy);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/taxonomies';
|
import { taxonomiesConfig } from '../../../src/static/js/utils/settings/taxonomies';
|
||||||
|
|
||||||
const taxonomiesConfig = (sett?: any) => {
|
describe('utils/settings', () => {
|
||||||
init(sett);
|
describe('taxonomies', () => {
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils-settings/taxonomies', () => {
|
|
||||||
test('Should return defaults when settings is undefined', () => {
|
test('Should return defaults when settings is undefined', () => {
|
||||||
const res = taxonomiesConfig();
|
const res = taxonomiesConfig();
|
||||||
expect(res).toStrictEqual({
|
expect(res).toStrictEqual({
|
||||||
@@ -19,9 +15,9 @@ describe('utils-settings/taxonomies', () => {
|
|||||||
expect(res.tags).toStrictEqual({ enabled: true, title: 'Tags' });
|
expect(res.tags).toStrictEqual({ enabled: true, title: 'Tags' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should keep taxonomy disabled when enabled is true', () => {
|
test('Should keep taxonomy disabled when enabled is explicitly false', () => {
|
||||||
const res = taxonomiesConfig({ categories: { enabled: true } });
|
const res = taxonomiesConfig({ categories: { enabled: false } });
|
||||||
expect(res.categories).toStrictEqual({ enabled: true, title: 'Categories' });
|
expect(res.categories).toStrictEqual({ enabled: false, title: 'Categories' });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should default to enabled=true when enabled is omitted but key exists', () => {
|
test('Should default to enabled=true when enabled is omitted but key exists', () => {
|
||||||
@@ -40,6 +36,7 @@ describe('utils-settings/taxonomies', () => {
|
|||||||
tags: { enabled: true, title: 'Tagz' },
|
tags: { enabled: true, title: 'Tagz' },
|
||||||
};
|
};
|
||||||
const res = taxonomiesConfig(input);
|
const res = taxonomiesConfig(input);
|
||||||
|
|
||||||
expect(res).toStrictEqual({
|
expect(res).toStrictEqual({
|
||||||
tags: { enabled: true, title: 'Tagz' },
|
tags: { enabled: true, title: 'Tagz' },
|
||||||
categories: { enabled: false, title: 'Categories' },
|
categories: { enabled: false, title: 'Categories' },
|
||||||
@@ -51,3 +48,4 @@ describe('utils-settings/taxonomies', () => {
|
|||||||
expect(res.categories).toStrictEqual({ enabled: true, title: 'Categories' });
|
expect(res.categories).toStrictEqual({ enabled: true, title: 'Categories' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import { init, settings } from '../../../src/static/js/utils/settings/theme';
|
import { themeConfig } from '../../../src/static/js/utils/settings/theme';
|
||||||
|
|
||||||
const themeConfig = (theme?: any, logo?: any) => {
|
|
||||||
init(theme, logo);
|
|
||||||
return settings();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('theme', () => {
|
describe('theme', () => {
|
||||||
@@ -18,10 +13,10 @@ describe('utils/settings', () => {
|
|||||||
|
|
||||||
test("Sets dark mode only when theme.mode is exactly 'dark' after trim", () => {
|
test("Sets dark mode only when theme.mode is exactly 'dark' after trim", () => {
|
||||||
expect(themeConfig({ mode: 'dark' }).mode).toBe('dark');
|
expect(themeConfig({ mode: 'dark' }).mode).toBe('dark');
|
||||||
expect(themeConfig({ mode: ' dark ' }).mode).toBe('dark');
|
expect(themeConfig({ mode: ' dark ' } as any).mode).toBe('dark');
|
||||||
expect(themeConfig({ mode: 'Dark' }).mode).toBe('light');
|
expect(themeConfig({ mode: 'Dark' } as any).mode).toBe('light');
|
||||||
expect(themeConfig({ mode: 'light' }).mode).toBe('light');
|
expect(themeConfig({ mode: 'light' }).mode).toBe('light');
|
||||||
expect(themeConfig({ mode: ' ' }).mode).toBe('light');
|
expect(themeConfig({ mode: ' ' } as any).mode).toBe('light');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Switch config: enabled only toggles off when explicitly false; position set to sidebar only when exactly sidebar after trim', () => {
|
test('Switch config: enabled only toggles off when explicitly false; position set to sidebar only when exactly sidebar after trim', () => {
|
||||||
@@ -30,9 +25,9 @@ describe('utils/settings', () => {
|
|||||||
expect(themeConfig({ switch: { enabled: undefined } }).switch.enabled).toBe(true);
|
expect(themeConfig({ switch: { enabled: undefined } }).switch.enabled).toBe(true);
|
||||||
|
|
||||||
expect(themeConfig({ switch: { position: 'sidebar' } }).switch.position).toBe('sidebar');
|
expect(themeConfig({ switch: { position: 'sidebar' } }).switch.position).toBe('sidebar');
|
||||||
expect(themeConfig({ switch: { position: ' sidebar ' } }).switch.position).toBe('header'); // @todo: Fix this. It should be 'sidebar'
|
expect(themeConfig({ switch: { position: ' sidebar ' } } as any).switch.position).toBe('sidebar');
|
||||||
expect(themeConfig({ switch: { position: 'header' } }).switch.position).toBe('header');
|
expect(themeConfig({ switch: { position: 'header' } }).switch.position).toBe('header');
|
||||||
expect(themeConfig({ switch: { position: 'foot' } }).switch.position).toBe('header');
|
expect(themeConfig({ switch: { position: 'foot' } } as any).switch.position).toBe('header');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Trims and maps logo URLs for both light and dark modes; ignores missing fields', () => {
|
test('Trims and maps logo URLs for both light and dark modes; ignores missing fields', () => {
|
||||||
@@ -63,7 +58,7 @@ describe('utils/settings', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Does not mutate input objects', () => {
|
test('Does not mutate input objects', () => {
|
||||||
const themeIn = { mode: ' dark ', switch: { enabled: false, position: ' sidebar ' } };
|
const themeIn: any = { mode: ' dark ', switch: { enabled: false, position: ' sidebar ' } };
|
||||||
const logoIn = { lightMode: { img: ' x ', svg: ' y ' }, darkMode: { img: ' z ', svg: ' w ' } };
|
const logoIn = { lightMode: { img: ' x ', svg: ' y ' }, darkMode: { img: ' z ', svg: ' w ' } };
|
||||||
const themeCopy = JSON.parse(JSON.stringify(themeIn));
|
const themeCopy = JSON.parse(JSON.stringify(themeIn));
|
||||||
const logoCopy = JSON.parse(JSON.stringify(logoIn));
|
const logoCopy = JSON.parse(JSON.stringify(logoIn));
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
import { init, pages } from '../../../src/static/js/utils/settings/url';
|
import { urlConfig } from '../../../src/static/js/utils/settings/url';
|
||||||
|
|
||||||
const urlConfig = (pages_url?: any) => {
|
|
||||||
init(pages_url);
|
|
||||||
return pages();
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('utils/settings', () => {
|
describe('utils/settings', () => {
|
||||||
describe('url', () => {
|
describe('url', () => {
|
||||||
const baseGlobal = {
|
const base = {
|
||||||
profileId: 'john',
|
profileId: 'john',
|
||||||
site: {
|
site: {
|
||||||
url: 'https://example.com/',
|
url: 'https://example.com/',
|
||||||
@@ -43,57 +38,81 @@ describe('utils/settings', () => {
|
|||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
test('Authenticated non-admin user', () => {
|
test('non-admin authenticated user: admin hidden, signout/changePassword visible, manage visible', () => {
|
||||||
const cfg = urlConfig(baseGlobal);
|
const cfg = urlConfig(base as any);
|
||||||
|
expect(cfg.admin).toBe('');
|
||||||
|
expect(cfg.signout).toBe('/signout');
|
||||||
|
expect(cfg.changePassword).toBe('/password');
|
||||||
|
expect(cfg.manage.media).toBe('/manage/media');
|
||||||
|
expect(cfg.manage.users).toBe('/manage/users');
|
||||||
|
expect(cfg.manage.comments).toBe('/manage/comments');
|
||||||
|
});
|
||||||
|
|
||||||
expect(cfg).toStrictEqual({
|
test('anonymous user: admin, signout, changePassword, manage all hidden', () => {
|
||||||
profileId: 'john',
|
const cfg = urlConfig({
|
||||||
site: { url: 'https://example.com/', devEnv: false },
|
...base,
|
||||||
url: {
|
user: { ...base.user, is: { anonymous: true, admin: false } },
|
||||||
home: '/',
|
} as any);
|
||||||
admin: '/admin',
|
expect(cfg.admin).toBe('');
|
||||||
error404: '/404',
|
expect(cfg.signout).toBe('');
|
||||||
latestMedia: '/latest',
|
expect(cfg.changePassword).toBe('');
|
||||||
featuredMedia: '/featured',
|
expect(cfg.manage.media).toBe('');
|
||||||
recommendedMedia: '/recommended',
|
expect(cfg.manage.users).toBe('');
|
||||||
signin: '/signin',
|
expect(cfg.manage.comments).toBe('');
|
||||||
signout: '/signout',
|
});
|
||||||
register: '/register',
|
|
||||||
changePassword: '/password',
|
test('admin user: admin visible', () => {
|
||||||
members: '/members',
|
const cfg = urlConfig({
|
||||||
search: '/search',
|
...base,
|
||||||
likedMedia: '/liked',
|
user: { ...base.user, is: { anonymous: false, admin: true } },
|
||||||
|
} as any);
|
||||||
|
expect(cfg.admin).toBe('/admin');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('embed URL strips trailing slashes from site.url', () => {
|
||||||
|
const cfg1 = urlConfig(base as any);
|
||||||
|
expect(cfg1.embed).toBe('https://example.com/embed?m=');
|
||||||
|
|
||||||
|
const cfg2 = urlConfig({ ...base, site: { ...base.site, url: 'https://example.com////' } } as any);
|
||||||
|
expect(cfg2.embed).toBe('https://example.com/embed?m=');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('search URLs are composed correctly', () => {
|
||||||
|
const cfg = urlConfig(base as any);
|
||||||
|
expect(cfg.search.base).toBe('/search');
|
||||||
|
expect(cfg.search.query).toBe('/search?q=');
|
||||||
|
expect(cfg.search.tag).toBe('/search?t=');
|
||||||
|
expect(cfg.search.category).toBe('/search?c=');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('profile URLs: devEnv=false use site.url + profileId', () => {
|
||||||
|
const cfg = urlConfig(base as any);
|
||||||
|
expect(cfg.profile.media).toBe('https://example.com/user/john');
|
||||||
|
expect(cfg.profile.about).toBe('https://example.com/user/john/about');
|
||||||
|
expect(cfg.profile.playlists).toBe('https://example.com/user/john/playlists');
|
||||||
|
expect(cfg.profile.shared_by_me).toBe('https://example.com/user/john/shared_by_me');
|
||||||
|
expect(cfg.profile.shared_with_me).toBe('https://example.com/user/john/shared_with_me');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('profile URLs: devEnv=true use user.pages and append shared paths', () => {
|
||||||
|
const cfg = urlConfig({ ...base, site: { ...base.site, devEnv: true } } as any);
|
||||||
|
expect(cfg.profile.media).toBe('/u/john');
|
||||||
|
expect(cfg.profile.about).toBe('/u/john/about');
|
||||||
|
expect(cfg.profile.playlists).toBe('/u/john/playlists');
|
||||||
|
expect(cfg.profile.shared_by_me).toBe('/u/john/shared_by_me');
|
||||||
|
expect(cfg.profile.shared_with_me).toBe('/u/john/shared_with_me');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('passes through archive and user URLs', () => {
|
||||||
|
const cfg = urlConfig(base as any);
|
||||||
|
expect(cfg.user).toStrictEqual({
|
||||||
|
liked: '/liked',
|
||||||
history: '/history',
|
history: '/history',
|
||||||
addMedia: '/add',
|
addMedia: '/add',
|
||||||
editChannel: '/edit/channel',
|
editChannel: '/edit/channel',
|
||||||
editProfile: '/edit/profile',
|
editProfile: '/edit/profile',
|
||||||
tags: '/tags',
|
|
||||||
categories: '/categories',
|
|
||||||
manageMedia: '/manage/media',
|
|
||||||
manageUsers: '/manage/users',
|
|
||||||
manageComments: '/manage/comments',
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
is: { anonymous: false, admin: false },
|
|
||||||
pages: { media: '/u/john', about: '/u/john/about', playlists: '/u/john/playlists' },
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
expect(cfg.archive).toStrictEqual({ tags: '/tags', categories: '/categories' });
|
||||||
|
|
||||||
test('Admin user', () => {
|
|
||||||
const cfg = urlConfig({
|
|
||||||
...baseGlobal,
|
|
||||||
user: { ...baseGlobal.user, is: { anonymous: false, admin: true } },
|
|
||||||
});
|
|
||||||
expect(cfg.user.is).toStrictEqual({ anonymous: false, admin: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Anonymous user', () => {
|
|
||||||
const cfg = urlConfig({
|
|
||||||
...baseGlobal,
|
|
||||||
user: { ...baseGlobal.user, is: { anonymous: true, admin: true } },
|
|
||||||
});
|
|
||||||
expect(cfg.user.is).toStrictEqual({ anonymous: true, admin: true });
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user