commit
4047a7ec23
378 changed files with 29334 additions and 0 deletions
29
pages/api/account/[id].js
Normal file
29
pages/api/account/[id].js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { getAccountById, deleteAccount } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
const { is_admin } = req.auth;
|
||||
const { id } = req.query;
|
||||
const user_id = +id;
|
||||
|
||||
if (!is_admin) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
if (req.method === 'GET') {
|
||||
const account = await getAccountById(user_id);
|
||||
|
||||
return ok(res, account);
|
||||
}
|
||||
|
||||
if (req.method === 'DELETE') {
|
||||
await deleteAccount(user_id);
|
||||
|
||||
return ok(res);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
61
pages/api/account/index.js
Normal file
61
pages/api/account/index.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { getAccountById, getAccountByUsername, updateAccount, createAccount } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { hashPassword } from 'lib/crypto';
|
||||
import { ok, unauthorized, methodNotAllowed, badRequest } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
const { user_id: current_user_id, is_admin: current_user_is_admin } = req.auth;
|
||||
|
||||
if (req.method === 'POST') {
|
||||
const { user_id, username, password, is_admin } = req.body;
|
||||
|
||||
if (user_id) {
|
||||
const account = await getAccountById(user_id);
|
||||
|
||||
if (account.user_id === current_user_id || current_user_is_admin) {
|
||||
const data = {};
|
||||
|
||||
if (password) {
|
||||
data.password = hashPassword(password);
|
||||
}
|
||||
|
||||
// Only admin can change these fields
|
||||
if (current_user_is_admin) {
|
||||
// Cannot change username of admin
|
||||
if (username !== 'admin') {
|
||||
data.username = username;
|
||||
}
|
||||
data.is_admin = is_admin;
|
||||
}
|
||||
|
||||
if (data.username && account.username !== data.username) {
|
||||
const accountByUsername = await getAccountByUsername(username);
|
||||
|
||||
if (accountByUsername) {
|
||||
return badRequest(res, 'Account already exists');
|
||||
}
|
||||
}
|
||||
|
||||
const updated = await updateAccount(user_id, data);
|
||||
|
||||
return ok(res, updated);
|
||||
}
|
||||
|
||||
return unauthorized(res);
|
||||
} else {
|
||||
const accountByUsername = await getAccountByUsername(username);
|
||||
|
||||
if (accountByUsername) {
|
||||
return badRequest(res, 'Account already exists');
|
||||
}
|
||||
|
||||
const created = await createAccount({ username, password: hashPassword(password) });
|
||||
|
||||
return ok(res, created);
|
||||
}
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
32
pages/api/account/password.js
Normal file
32
pages/api/account/password.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { getAccountById, updateAccount } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { badRequest, methodNotAllowed, ok, unauthorized } from 'lib/response';
|
||||
import { checkPassword, hashPassword } from 'lib/crypto';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
const { user_id: auth_user_id, is_admin } = req.auth;
|
||||
const { user_id, current_password, new_password } = req.body;
|
||||
|
||||
if (!is_admin && user_id !== auth_user_id) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
if (req.method === 'POST') {
|
||||
const account = await getAccountById(user_id);
|
||||
const valid = checkPassword(current_password, account.password);
|
||||
|
||||
if (!valid) {
|
||||
return badRequest(res, 'Current password is incorrect');
|
||||
}
|
||||
|
||||
const password = hashPassword(new_password);
|
||||
|
||||
const updated = await updateAccount(user_id, { password });
|
||||
|
||||
return ok(res, updated);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
21
pages/api/accounts.js
Normal file
21
pages/api/accounts.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { getAccounts } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { ok, unauthorized, methodNotAllowed } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
const { is_admin } = req.auth;
|
||||
|
||||
if (!is_admin) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
if (req.method === 'GET') {
|
||||
const accounts = await getAccounts();
|
||||
|
||||
return ok(res, accounts);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
32
pages/api/auth/login.js
Normal file
32
pages/api/auth/login.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { serialize } from 'cookie';
|
||||
import { checkPassword, createSecureToken } from 'lib/crypto';
|
||||
import { getAccountByUsername } from 'lib/queries';
|
||||
import { AUTH_COOKIE_NAME } from 'lib/constants';
|
||||
import { ok, unauthorized, badRequest } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
return badRequest(res);
|
||||
}
|
||||
|
||||
const account = await getAccountByUsername(username);
|
||||
|
||||
if (account && (await checkPassword(password, account.password))) {
|
||||
const { user_id, username, is_admin } = account;
|
||||
const token = await createSecureToken({ user_id, username, is_admin });
|
||||
const cookie = serialize(AUTH_COOKIE_NAME, token, {
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
sameSite: true,
|
||||
maxAge: 60 * 60 * 24 * 365,
|
||||
});
|
||||
|
||||
res.setHeader('Set-Cookie', [cookie]);
|
||||
|
||||
return ok(res, { token });
|
||||
}
|
||||
|
||||
return unauthorized(res);
|
||||
};
|
||||
15
pages/api/auth/logout.js
Normal file
15
pages/api/auth/logout.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { serialize } from 'cookie';
|
||||
import { AUTH_COOKIE_NAME } from 'lib/constants';
|
||||
import { ok } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
const cookie = serialize(AUTH_COOKIE_NAME, '', {
|
||||
path: '/',
|
||||
httpOnly: true,
|
||||
maxAge: 0,
|
||||
});
|
||||
|
||||
res.setHeader('Set-Cookie', [cookie]);
|
||||
|
||||
return ok(res);
|
||||
};
|
||||
12
pages/api/auth/verify.js
Normal file
12
pages/api/auth/verify.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { useAuth } from 'lib/middleware';
|
||||
import { ok, unauthorized } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
if (req.auth) {
|
||||
return ok(res, req.auth);
|
||||
}
|
||||
|
||||
return unauthorized(res);
|
||||
};
|
||||
60
pages/api/collect.js
Normal file
60
pages/api/collect.js
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import isbot from 'isbot';
|
||||
import ipaddr from 'ipaddr.js';
|
||||
import { savePageView, saveEvent } from 'lib/queries';
|
||||
import { useCors, useSession } from 'lib/middleware';
|
||||
import { getIpAddress } from 'lib/request';
|
||||
import { ok, badRequest } from 'lib/response';
|
||||
import { createToken } from 'lib/crypto';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useCors(req, res);
|
||||
|
||||
if (isbot(req.headers['user-agent'])) {
|
||||
return ok(res);
|
||||
}
|
||||
|
||||
if (process.env.IGNORE_IP) {
|
||||
const ips = process.env.IGNORE_IP.split(',').map(n => n.trim());
|
||||
const ip = getIpAddress(req);
|
||||
const blocked = ips.find(i => {
|
||||
if (i === ip) return true;
|
||||
|
||||
// CIDR notation
|
||||
if (i.indexOf('/') > 0) {
|
||||
const addr = ipaddr.parse(ip);
|
||||
const range = ipaddr.parseCIDR(i);
|
||||
|
||||
if (addr.kind() === range[0].kind() && addr.match(range)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (blocked) {
|
||||
return ok(res);
|
||||
}
|
||||
}
|
||||
|
||||
await useSession(req, res);
|
||||
|
||||
const { type, payload } = req.body;
|
||||
const {
|
||||
session: { website_id, session_id },
|
||||
} = req;
|
||||
|
||||
if (type === 'pageview') {
|
||||
const { url, referrer } = payload;
|
||||
|
||||
await savePageView(website_id, session_id, url, referrer);
|
||||
} else if (type === 'event') {
|
||||
const { url, event_type, event_value } = payload;
|
||||
|
||||
await saveEvent(website_id, session_id, url, event_type, event_value);
|
||||
} else {
|
||||
return badRequest(res);
|
||||
}
|
||||
|
||||
const token = await createToken({ website_id, session_id });
|
||||
|
||||
return ok(res, token);
|
||||
};
|
||||
26
pages/api/realtime/init.js
Normal file
26
pages/api/realtime/init.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { subMinutes } from 'date-fns';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { ok, methodNotAllowed } from 'lib/response';
|
||||
import { getUserWebsites, getRealtimeData } from 'lib/queries';
|
||||
import { createToken } from 'lib/crypto';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
if (req.method === 'GET') {
|
||||
const { user_id } = req.auth;
|
||||
|
||||
const websites = await getUserWebsites(user_id);
|
||||
const ids = websites.map(({ website_id }) => website_id);
|
||||
const token = await createToken({ websites: ids });
|
||||
const data = await getRealtimeData(ids, subMinutes(new Date(), 30));
|
||||
|
||||
return ok(res, {
|
||||
websites,
|
||||
token,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
27
pages/api/realtime/update.js
Normal file
27
pages/api/realtime/update.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { useAuth } from 'lib/middleware';
|
||||
import { ok, methodNotAllowed, badRequest } from 'lib/response';
|
||||
import { getRealtimeData } from 'lib/queries';
|
||||
import { parseToken } from 'lib/crypto';
|
||||
import { TOKEN_HEADER } from 'lib/constants';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
if (req.method === 'GET') {
|
||||
const { start_at } = req.query;
|
||||
|
||||
const token = req.headers[TOKEN_HEADER];
|
||||
|
||||
if (!token) {
|
||||
return badRequest(res);
|
||||
}
|
||||
|
||||
const { websites } = await parseToken(token);
|
||||
|
||||
const data = await getRealtimeData(websites, new Date(+start_at));
|
||||
|
||||
return ok(res, data);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
22
pages/api/share/[id].js
Normal file
22
pages/api/share/[id].js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { getWebsiteByShareId } from 'lib/queries';
|
||||
import { ok, notFound, methodNotAllowed } from 'lib/response';
|
||||
import { createToken } from 'lib/crypto';
|
||||
|
||||
export default async (req, res) => {
|
||||
const { id } = req.query;
|
||||
|
||||
if (req.method === 'GET') {
|
||||
const website = await getWebsiteByShareId(id);
|
||||
|
||||
if (website) {
|
||||
const websiteId = website.website_id;
|
||||
const token = await createToken({ website_id: websiteId });
|
||||
|
||||
return ok(res, { websiteId, token });
|
||||
}
|
||||
|
||||
return notFound(res);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
21
pages/api/website/[id]/active.js
Normal file
21
pages/api/website/[id]/active.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { getActiveVisitors } from 'lib/queries';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'lib/response';
|
||||
import { allowQuery } from 'lib/auth';
|
||||
|
||||
export default async (req, res) => {
|
||||
if (req.method === 'GET') {
|
||||
if (!(await allowQuery(req))) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const { id } = req.query;
|
||||
|
||||
const websiteId = +id;
|
||||
|
||||
const result = await getActiveVisitors(websiteId);
|
||||
|
||||
return ok(res, result);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
33
pages/api/website/[id]/events.js
Normal file
33
pages/api/website/[id]/events.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import moment from 'moment-timezone';
|
||||
import { getEventMetrics } from 'lib/queries';
|
||||
import { ok, badRequest, methodNotAllowed, unauthorized } from 'lib/response';
|
||||
import { allowQuery } from 'lib/auth';
|
||||
|
||||
const unitTypes = ['year', 'month', 'hour', 'day'];
|
||||
|
||||
export default async (req, res) => {
|
||||
if (req.method === 'GET') {
|
||||
if (!(await allowQuery(req))) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const { id, start_at, end_at, unit, tz, url, event_type } = req.query;
|
||||
|
||||
if (!moment.tz.zone(tz) || !unitTypes.includes(unit)) {
|
||||
return badRequest(res);
|
||||
}
|
||||
|
||||
const websiteId = +id;
|
||||
const startDate = new Date(+start_at);
|
||||
const endDate = new Date(+end_at);
|
||||
|
||||
const events = await getEventMetrics(websiteId, startDate, endDate, tz, unit, {
|
||||
url,
|
||||
event_type,
|
||||
});
|
||||
|
||||
return ok(res, events);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
31
pages/api/website/[id]/index.js
Normal file
31
pages/api/website/[id]/index.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { deleteWebsite, getWebsiteById } from 'lib/queries';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'lib/response';
|
||||
import { allowQuery } from 'lib/auth';
|
||||
|
||||
export default async (req, res) => {
|
||||
const { id } = req.query;
|
||||
|
||||
const websiteId = +id;
|
||||
|
||||
if (req.method === 'GET') {
|
||||
if (!(await allowQuery(req))) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const website = await getWebsiteById(websiteId);
|
||||
|
||||
return ok(res, website);
|
||||
}
|
||||
|
||||
if (req.method === 'DELETE') {
|
||||
if (!(await allowQuery(req, true))) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
await deleteWebsite(websiteId);
|
||||
|
||||
return ok(res);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
74
pages/api/website/[id]/metrics.js
Normal file
74
pages/api/website/[id]/metrics.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import { getPageviewMetrics, getSessionMetrics, getWebsiteById } from 'lib/queries';
|
||||
import { ok, methodNotAllowed, unauthorized, badRequest } from 'lib/response';
|
||||
import { allowQuery } from 'lib/auth';
|
||||
|
||||
const sessionColumns = ['browser', 'os', 'device', 'country'];
|
||||
const pageviewColumns = ['url', 'referrer'];
|
||||
|
||||
function getTable(type) {
|
||||
if (type === 'event') {
|
||||
return 'event';
|
||||
}
|
||||
|
||||
if (sessionColumns.includes(type)) {
|
||||
return 'session';
|
||||
}
|
||||
|
||||
return 'pageview';
|
||||
}
|
||||
|
||||
function getColumn(type) {
|
||||
if (type === 'event') {
|
||||
return `concat(event_type, '\t', event_value)`;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
export default async (req, res) => {
|
||||
if (req.method === 'GET') {
|
||||
if (!(await allowQuery(req))) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const { id, type, start_at, end_at, url } = req.query;
|
||||
|
||||
const websiteId = +id;
|
||||
const startDate = new Date(+start_at);
|
||||
const endDate = new Date(+end_at);
|
||||
|
||||
if (sessionColumns.includes(type)) {
|
||||
const data = await getSessionMetrics(websiteId, startDate, endDate, type, { url });
|
||||
|
||||
return ok(res, data);
|
||||
}
|
||||
|
||||
if (pageviewColumns.includes(type) || type === 'event') {
|
||||
let domain;
|
||||
if (type === 'referrer') {
|
||||
const website = getWebsiteById(websiteId);
|
||||
|
||||
if (!website) {
|
||||
return badRequest(res);
|
||||
}
|
||||
|
||||
domain = website.domain;
|
||||
}
|
||||
|
||||
const data = await getPageviewMetrics(
|
||||
websiteId,
|
||||
startDate,
|
||||
endDate,
|
||||
getColumn(type),
|
||||
getTable(type),
|
||||
{
|
||||
domain,
|
||||
url: type !== 'url' && url,
|
||||
},
|
||||
);
|
||||
|
||||
return ok(res, data);
|
||||
}
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
36
pages/api/website/[id]/pageviews.js
Normal file
36
pages/api/website/[id]/pageviews.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import moment from 'moment-timezone';
|
||||
import { getPageviewStats } from 'lib/queries';
|
||||
import { ok, badRequest, methodNotAllowed, unauthorized } from 'lib/response';
|
||||
import { allowQuery } from 'lib/auth';
|
||||
|
||||
const unitTypes = ['year', 'month', 'hour', 'day'];
|
||||
|
||||
export default async (req, res) => {
|
||||
if (req.method === 'GET') {
|
||||
if (!(await allowQuery(req))) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const { id, start_at, end_at, unit, tz, url, ref } = req.query;
|
||||
|
||||
const websiteId = +id;
|
||||
const startDate = new Date(+start_at);
|
||||
const endDate = new Date(+end_at);
|
||||
|
||||
if (!moment.tz.zone(tz) || !unitTypes.includes(unit)) {
|
||||
return badRequest(res);
|
||||
}
|
||||
|
||||
const [pageviews, sessions] = await Promise.all([
|
||||
getPageviewStats(websiteId, startDate, endDate, tz, unit, '*', { url, ref }),
|
||||
getPageviewStats(websiteId, startDate, endDate, tz, unit, 'distinct session_id', {
|
||||
url,
|
||||
ref,
|
||||
}),
|
||||
]);
|
||||
|
||||
return ok(res, { pageviews, sessions });
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
20
pages/api/website/[id]/reset.js
Normal file
20
pages/api/website/[id]/reset.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { resetWebsite } from 'lib/queries';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'lib/response';
|
||||
import { allowQuery } from 'lib/auth';
|
||||
|
||||
export default async (req, res) => {
|
||||
const { id } = req.query;
|
||||
const websiteId = +id;
|
||||
|
||||
if (req.method === 'POST') {
|
||||
if (!(await allowQuery(req))) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
await resetWebsite(websiteId);
|
||||
|
||||
return ok(res);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
36
pages/api/website/[id]/stats.js
Normal file
36
pages/api/website/[id]/stats.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { getWebsiteStats } from 'lib/queries';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'lib/response';
|
||||
import { allowQuery } from 'lib/auth';
|
||||
|
||||
export default async (req, res) => {
|
||||
if (req.method === 'GET') {
|
||||
if (!(await allowQuery(req))) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const { id, start_at, end_at, url, ref } = req.query;
|
||||
|
||||
const websiteId = +id;
|
||||
const startDate = new Date(+start_at);
|
||||
const endDate = new Date(+end_at);
|
||||
|
||||
const distance = end_at - start_at;
|
||||
const prevStartDate = new Date(+start_at - distance);
|
||||
const prevEndDate = new Date(+end_at - distance);
|
||||
|
||||
const metrics = await getWebsiteStats(websiteId, startDate, endDate, { url, ref });
|
||||
const prevPeriod = await getWebsiteStats(websiteId, prevStartDate, prevEndDate, { url, ref });
|
||||
|
||||
const stats = Object.keys(metrics[0]).reduce((obj, key) => {
|
||||
obj[key] = {
|
||||
value: Number(metrics[0][key]) || 0,
|
||||
change: Number(metrics[0][key] - prevPeriod[0][key]) || 0,
|
||||
};
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
return ok(res, stats);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
43
pages/api/website/index.js
Normal file
43
pages/api/website/index.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { updateWebsite, createWebsite, getWebsiteById } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { uuid, getRandomChars } from 'lib/crypto';
|
||||
import { ok, unauthorized, methodNotAllowed } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
const { user_id, is_admin } = req.auth;
|
||||
const { website_id, enable_share_url } = req.body;
|
||||
|
||||
if (req.method === 'POST') {
|
||||
const { name, domain } = req.body;
|
||||
|
||||
if (website_id) {
|
||||
const website = await getWebsiteById(website_id);
|
||||
|
||||
if (website.user_id !== user_id && !is_admin) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
let { share_id } = website;
|
||||
|
||||
if (enable_share_url) {
|
||||
share_id = share_id ? share_id : getRandomChars(8);
|
||||
} else {
|
||||
share_id = null;
|
||||
}
|
||||
|
||||
await updateWebsite(website_id, { name, domain, share_id });
|
||||
|
||||
return ok(res);
|
||||
} else {
|
||||
const website_uuid = uuid();
|
||||
const share_id = enable_share_url ? getRandomChars(8) : null;
|
||||
const website = await createWebsite(user_id, { website_uuid, name, domain, share_id });
|
||||
|
||||
return ok(res, website);
|
||||
}
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
23
pages/api/websites.js
Normal file
23
pages/api/websites.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import { getUserWebsites } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { ok, methodNotAllowed, unauthorized } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
const { user_id: current_user_id, is_admin } = req.auth;
|
||||
const { user_id } = req.query;
|
||||
const userId = +user_id;
|
||||
|
||||
if (req.method === 'GET') {
|
||||
if (userId && userId !== current_user_id && !is_admin) {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const websites = await getUserWebsites(userId || current_user_id);
|
||||
|
||||
return ok(res, websites);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue