Merge remote-tracking branch 'origin/master' into dev
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 28s
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 28s
This commit is contained in:
commit
7098c335bc
2
f0ck.sql
2
f0ck.sql
|
@ -131,7 +131,7 @@ CREATE TABLE public."user" (
|
||||||
login character varying(255) NOT NULL,
|
login character varying(255) NOT NULL,
|
||||||
"user" character varying(255) NOT NULL,
|
"user" character varying(255) NOT NULL,
|
||||||
password character varying(167) NOT NULL,
|
password character varying(167) NOT NULL,
|
||||||
level integer NOT NULL
|
admin boolean NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
ALTER TABLE public."user" OWNER TO f0ck;
|
ALTER TABLE public."user" OWNER TO f0ck;
|
||||||
|
|
|
@ -333,7 +333,8 @@ const flash = ({ type, msg }) => {
|
||||||
document.querySelector("a#a_toggle").addEventListener("click", toggleEvent);
|
document.querySelector("a#a_toggle").addEventListener("click", toggleEvent);
|
||||||
[...document.querySelectorAll("#tags > .badge > a:first-child")].map(t => t.addEventListener("click", editTagEvent));
|
[...document.querySelectorAll("#tags > .badge > a:first-child")].map(t => t.addEventListener("click", editTagEvent));
|
||||||
[...document.querySelectorAll("#tags > .badge > a:last-child")].map(t => t.addEventListener("click", deleteEvent));
|
[...document.querySelectorAll("#tags > .badge > a:last-child")].map(t => t.addEventListener("click", deleteEvent));
|
||||||
document.querySelector("svg#a_delete").addEventListener("click", deleteButtonEvent);
|
if(document.querySelector("svg#a_delete"))
|
||||||
|
document.querySelector("svg#a_delete").addEventListener("click", deleteButtonEvent);
|
||||||
document.querySelector("svg#a_favo").addEventListener("click", toggleFavEvent);
|
document.querySelector("svg#a_favo").addEventListener("click", toggleFavEvent);
|
||||||
|
|
||||||
document.addEventListener("keyup", e => {
|
document.addEventListener("keyup", e => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import _config from "../../config.json" assert { type: "json" };
|
import _config from "../../config.json" with { type: "json" };
|
||||||
|
|
||||||
let config = JSON.parse(JSON.stringify(_config));
|
let config = JSON.parse(JSON.stringify(_config));
|
||||||
|
|
||||||
|
|
|
@ -134,15 +134,6 @@ export default new class {
|
||||||
const derivedKey = await scrypt(str, salt, 64);
|
const derivedKey = await scrypt(str, salt, 64);
|
||||||
return crypto.timingSafeEqual(keyBuffer, derivedKey);
|
return crypto.timingSafeEqual(keyBuffer, derivedKey);
|
||||||
};
|
};
|
||||||
async auth(req, res, next) {
|
|
||||||
if(!req.session) {
|
|
||||||
return res.reply({
|
|
||||||
code: 401,
|
|
||||||
body: "401 - Unauthorized"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return next();
|
|
||||||
};
|
|
||||||
async getTags(itemid) {
|
async getTags(itemid) {
|
||||||
const tags = await db`
|
const tags = await db`
|
||||||
select "tags".id, "tags".tag, "tags".normalized, "user".user
|
select "tags".id, "tags".tag, "tags".normalized, "user".user
|
||||||
|
@ -217,6 +208,27 @@ export default new class {
|
||||||
TABLE_NAME='user_options' and
|
TABLE_NAME='user_options' and
|
||||||
COLUMN_NAME = 'avatar'
|
COLUMN_NAME = 'avatar'
|
||||||
`)[0].avatar;
|
`)[0].avatar;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// meddlware
|
||||||
|
async auth(req, res, next) {
|
||||||
|
if(!req.session || !req.session.admin) {
|
||||||
|
return res.reply({
|
||||||
|
code: 401,
|
||||||
|
body: "401 - Unauthorized"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return next();
|
||||||
|
};
|
||||||
|
|
||||||
|
async loggedin(req, res, next) {
|
||||||
|
if(!req.session) {
|
||||||
|
return res.reply({
|
||||||
|
code: 401,
|
||||||
|
body: "401 - Unauthorized"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return next();
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,12 +7,13 @@ import url from "url";
|
||||||
const globalfilter = cfg.nsfp.map(n => `tag_id = ${n}`).join(' or ');
|
const globalfilter = cfg.nsfp.map(n => `tag_id = ${n}`).join(' or ');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getf0cks: async (o = { user, tag, mime, page, mode, fav, session }) => {
|
getf0cks: async (o = { user, tag, mime, page, mode, fav, session, limit }) => {
|
||||||
const user = o.user ? decodeURI(o.user) : null;
|
const user = o.user ? decodeURI(o.user) : null;
|
||||||
const tag = lib.parseTag(o.tag ?? null);
|
const tag = lib.parseTag(o.tag ?? null);
|
||||||
const mime = o.mime ?? null;
|
const mime = o.mime ?? null;
|
||||||
const page = +(o.page ?? 1);
|
const page = +(o.page ?? 1);
|
||||||
const smime = cfg.allowedMimes.includes(mime) ? mime + "/%" : mime === "" ? "%" : "%";
|
const smime = cfg.allowedMimes.includes(mime) ? mime + "/%" : mime === "" ? "%" : "%";
|
||||||
|
const eps = o.limit ?? cfg.websrv.eps;
|
||||||
|
|
||||||
const tmp = { user, tag, mime, smime, page, mode: o.mode };
|
const tmp = { user, tag, mime, smime, page, mode: o.mode };
|
||||||
const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0);
|
const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0);
|
||||||
|
@ -70,7 +71,7 @@ export default {
|
||||||
group by items.id, tags.tag, ta.tag_id
|
group by items.id, tags.tag, ta.tag_id
|
||||||
order by items.id desc
|
order by items.id desc
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
limit ${cfg.websrv.eps}
|
limit ${eps}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const cheat = [];
|
const cheat = [];
|
||||||
|
|
|
@ -3,18 +3,7 @@ import lib from "../lib.mjs";
|
||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
import { promises as fs } from "fs";
|
import { promises as fs } from "fs";
|
||||||
|
|
||||||
const auth = async (req, res, next) => {
|
|
||||||
if(!req.session) {
|
|
||||||
return res.reply({
|
|
||||||
code: 401,
|
|
||||||
body: "401 - Unauthorized"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return next();
|
|
||||||
};
|
|
||||||
|
|
||||||
export default (router, tpl) => {
|
export default (router, tpl) => {
|
||||||
|
|
||||||
router.get(/^\/login(\/)?$/, async (req, res) => {
|
router.get(/^\/login(\/)?$/, async (req, res) => {
|
||||||
if(req.cookies.session) {
|
if(req.cookies.session) {
|
||||||
return res.reply({
|
return res.reply({
|
||||||
|
@ -72,7 +61,7 @@ export default (router, tpl) => {
|
||||||
}).end();
|
}).end();
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get(/^\/logout$/, auth, async (req, res) => {
|
router.get(/^\/logout$/, lib.loggedin, async (req, res) => {
|
||||||
const usersession = await db`
|
const usersession = await db`
|
||||||
select *
|
select *
|
||||||
from "user_sessions"
|
from "user_sessions"
|
||||||
|
@ -103,7 +92,7 @@ export default (router, tpl) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get(/^\/admin(\/)?$/, auth, async (req, res) => { // frontpage
|
router.get(/^\/admin(\/)?$/, lib.auth, async (req, res) => { // frontpage
|
||||||
|
|
||||||
res.reply({
|
res.reply({
|
||||||
body: tpl.render("admin", {
|
body: tpl.render("admin", {
|
||||||
|
@ -114,7 +103,7 @@ export default (router, tpl) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get(/^\/admin\/sessions(\/)?$/, auth, async (req, res) => {
|
router.get(/^\/admin\/sessions(\/)?$/, lib.auth, async (req, res) => {
|
||||||
const rows = await db`
|
const rows = await db`
|
||||||
select "user_sessions".*, "user".user
|
select "user_sessions".*, "user".user
|
||||||
from "user_sessions"
|
from "user_sessions"
|
||||||
|
@ -132,7 +121,7 @@ export default (router, tpl) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get(/^\/admin\/log(\/)?$/, auth, async (req, res) => {
|
router.get(/^\/admin\/log(\/)?$/, lib.auth, async (req, res) => {
|
||||||
exec("journalctl -qeu f0ck --no-pager", (err, stdout) => {
|
exec("journalctl -qeu f0ck --no-pager", (err, stdout) => {
|
||||||
res.reply({
|
res.reply({
|
||||||
body: tpl.render("admin/log", {
|
body: tpl.render("admin/log", {
|
||||||
|
@ -143,7 +132,7 @@ export default (router, tpl) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get(/^\/admin\/recover\/?/, auth, async (req, res) => {
|
router.get(/^\/admin\/recover\/?/, lib.auth, async (req, res) => {
|
||||||
if(req.url.qs?.id) {
|
if(req.url.qs?.id) {
|
||||||
const id = +req.url.qs.id;
|
const id = +req.url.qs.id;
|
||||||
const f0ck = await db`
|
const f0ck = await db`
|
||||||
|
|
|
@ -139,7 +139,7 @@ export default router => {
|
||||||
|
|
||||||
// tags lol
|
// tags lol
|
||||||
|
|
||||||
group.put(/\/admin\/tags\/(?<tagname>.*)/, lib.auth, async (req, res) => {
|
group.put(/\/admin\/tags\/(?<tagname>.*)/, lib.loggedin, async (req, res) => {
|
||||||
if(!req.params.tagname || !req.post.newtag) {
|
if(!req.params.tagname || !req.post.newtag) {
|
||||||
return res.json({
|
return res.json({
|
||||||
success: false,
|
success: false,
|
||||||
|
@ -187,7 +187,7 @@ export default router => {
|
||||||
return res.json(q, tagname === newtag ? 200 : 201); // created (modified)
|
return res.json(q, tagname === newtag ? 200 : 201); // created (modified)
|
||||||
});
|
});
|
||||||
|
|
||||||
group.get(/\/admin\/tags\/suggest$/, lib.auth, async (req, res) => {
|
group.get(/\/admin\/tags\/suggest$/, lib.loggedin, async (req, res) => {
|
||||||
const reply = {
|
const reply = {
|
||||||
success: false,
|
success: false,
|
||||||
suggestions: {}
|
suggestions: {}
|
||||||
|
@ -267,7 +267,7 @@ export default router => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group.post(/\/admin\/togglefav$/, lib.auth, async (req, res) => {
|
group.post(/\/admin\/togglefav$/, lib.loggedin, async (req, res) => {
|
||||||
const postid = +req.post.postid;
|
const postid = +req.post.postid;
|
||||||
|
|
||||||
let favs = await db`
|
let favs = await db`
|
||||||
|
|
|
@ -3,7 +3,7 @@ import lib from '../../lib.mjs';
|
||||||
|
|
||||||
export default router => {
|
export default router => {
|
||||||
router.group(/^\/api\/v2\/settings/, group => {
|
router.group(/^\/api\/v2\/settings/, group => {
|
||||||
group.put(/\/setAvatar/, lib.auth, async (req, res) => {
|
group.put(/\/setAvatar/, lib.loggedin, async (req, res) => {
|
||||||
if(!req.post.avatar) {
|
if(!req.post.avatar) {
|
||||||
return res.json({
|
return res.json({
|
||||||
msg: 'no avatar provided',
|
msg: 'no avatar provided',
|
||||||
|
|
|
@ -3,7 +3,7 @@ import lib from '../../lib.mjs';
|
||||||
|
|
||||||
export default router => {
|
export default router => {
|
||||||
router.group(/^\/api\/v2\/admin\/(?<postid>\d+)\/tags/, group => {
|
router.group(/^\/api\/v2\/admin\/(?<postid>\d+)\/tags/, group => {
|
||||||
group.get(/$/, lib.auth, async (req, res) => {
|
group.get(/$/, lib.loggedin, async (req, res) => {
|
||||||
// get tags
|
// get tags
|
||||||
if(!req.params.postid) {
|
if(!req.params.postid) {
|
||||||
return res.json({
|
return res.json({
|
||||||
|
@ -18,7 +18,7 @@ export default router => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group.post(/$/, lib.auth, async (req, res) => {
|
group.post(/$/, lib.loggedin, async (req, res) => {
|
||||||
// assign and/or create tag
|
// assign and/or create tag
|
||||||
if(!req.params.postid || !req.post.tagname) {
|
if(!req.params.postid || !req.post.tagname) {
|
||||||
return res.json({
|
return res.json({
|
||||||
|
@ -80,7 +80,7 @@ export default router => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group.put(/\/toggle$/, lib.auth, async (req, res) => {
|
group.put(/\/toggle$/, lib.loggedin, async (req, res) => {
|
||||||
// xD
|
// xD
|
||||||
if(!req.params.postid) {
|
if(!req.params.postid) {
|
||||||
return res.json({
|
return res.json({
|
||||||
|
|
|
@ -14,7 +14,7 @@ export default (router, tpl) => {
|
||||||
const user = decodeURIComponent(req.params.user);
|
const user = decodeURIComponent(req.params.user);
|
||||||
|
|
||||||
const query = await db`
|
const query = await db`
|
||||||
select "user".user, "user".created_at, user_options.*
|
select "user".user, "user".admin, "user".created_at, user_options.*
|
||||||
from user_options
|
from user_options
|
||||||
left join "user" on "user".id = user_options.user_id
|
left join "user" on "user".id = user_options.user_id
|
||||||
where "user".user ilike ${user}
|
where "user".user ilike ${user}
|
||||||
|
@ -31,31 +31,42 @@ export default (router, tpl) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const f0cks = await f0cklib.getf0cks({
|
let f0cks, favs;
|
||||||
user: user,
|
|
||||||
mode: req.session.mode,
|
|
||||||
fav: false,
|
|
||||||
session: !!req.session
|
|
||||||
});
|
|
||||||
const favs = await f0cklib.getf0cks({
|
|
||||||
user: user,
|
|
||||||
mode: req.session.mode,
|
|
||||||
fav: true,
|
|
||||||
session: !!req.session
|
|
||||||
});
|
|
||||||
|
|
||||||
const count = {
|
const count = {
|
||||||
f0cks: 0,
|
f0cks: 0,
|
||||||
favs: 0
|
favs: 0
|
||||||
};
|
};
|
||||||
|
try {
|
||||||
if('items' in f0cks) {
|
f0cks = await f0cklib.getf0cks({
|
||||||
count.f0cks = f0cks.items.length;
|
user: user,
|
||||||
f0cks.items = f0cks.items.slice(0, 50);
|
mode: req.session.mode,
|
||||||
|
fav: false,
|
||||||
|
session: !!req.session,
|
||||||
|
limit: 99999999
|
||||||
|
});
|
||||||
|
if('items' in f0cks) {
|
||||||
|
count.f0cks = f0cks.items.length;
|
||||||
|
f0cks.items = f0cks.items.slice(0, 50);
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
f0cks = false;
|
||||||
|
count.f0cks = 0;
|
||||||
}
|
}
|
||||||
if('items' in favs) {
|
try {
|
||||||
count.favs = favs.items.length;
|
favs = await f0cklib.getf0cks({
|
||||||
favs.items = favs.items.slice(0, 50);
|
user: user,
|
||||||
|
mode: req.session.mode,
|
||||||
|
fav: true,
|
||||||
|
session: !!req.session,
|
||||||
|
limit: 99999999
|
||||||
|
});
|
||||||
|
if('items' in favs) {
|
||||||
|
count.favs = favs.items.length;
|
||||||
|
favs.items = favs.items.slice(0, 50);
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
favs = false;
|
||||||
|
count.favs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -100,7 +111,7 @@ export default (router, tpl) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get(/^\/mode\/(\d)/, auth, async (req, res) => {
|
router.get(/^\/mode\/(\d)/, lib.loggedin, async (req, res) => {
|
||||||
const mode = +req.url.split[1];
|
const mode = +req.url.split[1];
|
||||||
let referertmp = req.headers.referer;
|
let referertmp = req.headers.referer;
|
||||||
let referer = "";
|
let referer = "";
|
||||||
|
|
26
src/inc/routes/picdump.mjs
Normal file
26
src/inc/routes/picdump.mjs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import db from "../../inc/sql.mjs";
|
||||||
|
import cfg from "../../inc/config.mjs";
|
||||||
|
import f0cklib from "../routeinc/f0cklib.mjs";
|
||||||
|
|
||||||
|
export default (router, tpl) => {
|
||||||
|
router.get(/^\/picdump$/, async (req, res) => {
|
||||||
|
const dump = await db`
|
||||||
|
SELECT *
|
||||||
|
FROM items
|
||||||
|
WHERE (
|
||||||
|
to_timestamp(stamp) >= date_trunc('week', CURRENT_TIMESTAMP - interval '1 week') AND
|
||||||
|
to_timestamp(stamp) < date_trunc('week', CURRENT_TIMESTAMP)
|
||||||
|
) AND
|
||||||
|
mime LIKE 'image/%'
|
||||||
|
ORDER BY stamp DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
res.reply({
|
||||||
|
body: tpl.render('picdump', {
|
||||||
|
dump,
|
||||||
|
tmp: null
|
||||||
|
}, req)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return router;
|
||||||
|
};
|
|
@ -8,13 +8,13 @@ export default (router, tpl) => {
|
||||||
try {
|
try {
|
||||||
const list = await db`
|
const list = await db`
|
||||||
select
|
select
|
||||||
"user".user,
|
"user".user, "user".admin,
|
||||||
coalesce("user_options".avatar, ${await lib.getDefaultAvatar()}) as avatar,
|
coalesce("user_options".avatar, ${await lib.getDefaultAvatar()}) as avatar,
|
||||||
count(distinct(tag_id, item_id)) as count
|
count(distinct(tag_id, item_id)) as count
|
||||||
from "tags_assign"
|
from "tags_assign"
|
||||||
left join "user" on "user".id = "tags_assign".user_id
|
left join "user" on "user".id = "tags_assign".user_id
|
||||||
left join "user_options" on "user_options".user_id = "user".id
|
left join "user_options" on "user_options".user_id = "user".id
|
||||||
group by "user".user, "user_options".avatar
|
group by "user".user, "user_options".avatar, "user".admin
|
||||||
order by count desc
|
order by count desc
|
||||||
`;
|
`;
|
||||||
const stats = await lib.countf0cks();
|
const stats = await lib.countf0cks();
|
||||||
|
|
|
@ -5,7 +5,7 @@ import search from "../routeinc/search.mjs";
|
||||||
const _eps = 20;
|
const _eps = 20;
|
||||||
|
|
||||||
export default (router, tpl) => {
|
export default (router, tpl) => {
|
||||||
router.get(/^\/search(\/)?$/, lib.auth, async (req, res) => {
|
router.get(/^\/search(\/)?$/, lib.loggedin, async (req, res) => {
|
||||||
let ret;
|
let ret;
|
||||||
let tag = req.url.qs.tag ?? [];
|
let tag = req.url.qs.tag ?? [];
|
||||||
let page = req.url.qs.page ?? 1;
|
let page = req.url.qs.page ?? 1;
|
||||||
|
|
|
@ -211,6 +211,19 @@ export default async bot => {
|
||||||
await fs.promises.copyFile(source, `./public/b/${filename}`);
|
await fs.promises.copyFile(source, `./public/b/${filename}`);
|
||||||
await fs.promises.unlink(source).catch(_=>{});
|
await fs.promises.unlink(source).catch(_=>{});
|
||||||
|
|
||||||
|
// user alias
|
||||||
|
let username = e.user.nick || e.user.username;
|
||||||
|
const alias = (await db`
|
||||||
|
select "user"."user"
|
||||||
|
from "user_alias"
|
||||||
|
join "user" on "user".id = user_alias.userid
|
||||||
|
where lower(user_alias.alias) ilike ${username}
|
||||||
|
limit 1
|
||||||
|
`)?.[0]?.user;
|
||||||
|
if(alias) {
|
||||||
|
username = alias;
|
||||||
|
}
|
||||||
|
|
||||||
await db`
|
await db`
|
||||||
insert into items ${
|
insert into items ${
|
||||||
db({
|
db({
|
||||||
|
@ -219,7 +232,7 @@ export default async bot => {
|
||||||
mime: mime,
|
mime: mime,
|
||||||
size: size,
|
size: size,
|
||||||
checksum: checksum,
|
checksum: checksum,
|
||||||
username: e.user.nick || e.user.username,
|
username: username,
|
||||||
userchannel: e.channel,
|
userchannel: e.channel,
|
||||||
usernetwork: e.network,
|
usernetwork: e.network,
|
||||||
stamp: ~~(new Date() / 1000),
|
stamp: ~~(new Date() / 1000),
|
||||||
|
|
|
@ -71,7 +71,7 @@ process.on('unhandledRejection', err => {
|
||||||
|
|
||||||
if(req.cookies.session) {
|
if(req.cookies.session) {
|
||||||
const user = await db`
|
const user = await db`
|
||||||
select "user".id, "user".login, "user".user, "user".level, "user_sessions".id as sess_id, "user_options".*
|
select "user".id, "user".login, "user".user, "user".admin, "user_sessions".id as sess_id, "user_options".*
|
||||||
from "user_sessions"
|
from "user_sessions"
|
||||||
left join "user" on "user".id = "user_sessions".user_id
|
left join "user" on "user".id = "user_sessions".user_id
|
||||||
left join "user_options" on "user_options".user_id = "user_sessions".user_id
|
left join "user_options" on "user_options".user_id = "user_sessions".user_id
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="pagewrapper">
|
<div class="pagewrapper">
|
||||||
<div id="main">
|
<div id="main">
|
||||||
<div class="index-container">
|
<div class="index-container">
|
||||||
@if(tmp.user)<h2>user: {!! tmp.user.toLowerCase() !!}@if(tmp.mime) ({{ tmp.mime }}s)@else (all)@endif</h2>@endif
|
@if(tmp.user)<h2>user: <a href="/user/{{ tmp.user.toLowerCase() }}">{!! tmp.user.toLowerCase() !!}</a>@if(tmp.mime) ({{ tmp.mime }}s)@else (all)@endif</h2>@endif
|
||||||
@if(tmp.tag)<h2>tag: @if(session)<a href="/search?tag={!! tmp.tag.toLowerCase() !!}" target="_blank">{!! tmp.tag.toLowerCase() !!}</a>@else{!! tmp.tag.toLowerCase() !!}@endif@if(tmp.mime) ({{ tmp.mime }}s)@else (all)@endif</h2>@endif
|
@if(tmp.tag)<h2>tag: @if(session)<a href="/search?tag={!! tmp.tag.toLowerCase() !!}" target="_blank">{!! tmp.tag.toLowerCase() !!}</a>@else{!! tmp.tag.toLowerCase() !!}@endif@if(tmp.mime) ({{ tmp.mime }}s)@else (all)@endif</h2>@endif
|
||||||
<div class="posts">
|
<div class="posts">
|
||||||
@each(items as item)
|
@each(items as item)
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<div class="gapRight">
|
<div class="gapRight">
|
||||||
<svg class="iconset" id="a_favo"><use href="/s/img/iconset.svg#heart_{{ Object.values(item.favorites).filter(u => u.user == session.user)[0] ? 'solid' : 'regular' }}"></use></svg>
|
<svg class="iconset" id="a_favo"><use href="/s/img/iconset.svg#heart_{{ Object.values(item.favorites).filter(u => u.user == session.user)[0] ? 'solid' : 'regular' }}"></use></svg>
|
||||||
<svg class="iconset" id="a_tfull"><use href="/s/img/iconset.svg#window-{{ fullscreen == 1 ? 'minimize' : 'maximize' }}"></use></svg>
|
<svg class="iconset" id="a_tfull"><use href="/s/img/iconset.svg#window-{{ fullscreen == 1 ? 'minimize' : 'maximize' }}"></use></svg>
|
||||||
<svg class="iconset" id="a_delete"><use href="/s/img/iconset.svg#cross"></use></svg>
|
@if(session.admin)<svg class="iconset" id="a_delete"><use href="/s/img/iconset.svg#cross"></use></svg>@endif
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
@ -83,7 +83,7 @@
|
||||||
@if(typeof item.tags !== "undefined")
|
@if(typeof item.tags !== "undefined")
|
||||||
@each(item.tags as tag)
|
@each(item.tags as tag)
|
||||||
<span @if(session)tooltip="{{ tag.user }}"@endif class="badge {{ tag.badge }} mr-2">
|
<span @if(session)tooltip="{{ tag.user }}"@endif class="badge {{ tag.badge }} mr-2">
|
||||||
<a href="/tag/{{ tag.normalized }}">{!! tag.tag !!}</a>@if(session) <a class="removetag" href="#">×</a>@endif
|
<a href="/tag/{{ tag.normalized }}">{!! tag.tag !!}</a>@if(session.admin) <a class="removetag" href="#">×</a>@endif
|
||||||
</span>
|
</span>
|
||||||
@endeach
|
@endeach
|
||||||
@endif
|
@endif
|
||||||
|
|
22
views/picdump.html
Normal file
22
views/picdump.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
@include(snippets/header)
|
||||||
|
<div id="main">
|
||||||
|
<h2>Picdump (last week)</h2>
|
||||||
|
<div class="picdump">
|
||||||
|
@each(dump as line)
|
||||||
|
<a href="/{{ line.id }}"><img src="/t/{{ line.id }}.webp"></a>
|
||||||
|
@endeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
.picdump {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.picdump > a {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
.picdump > a > img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@include(snippets/footer)
|
|
@ -11,8 +11,8 @@
|
||||||
@for(let i = 0; i < list.length; i++)
|
@for(let i = 0; i < list.length; i++)
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ i + 1 }}</td>
|
<td>{{ i + 1 }}</td>
|
||||||
<td><a href="/{{ list[i].avatar }}"><img class="avatar" src="/t/{{ list[i].avatar }}.webp" /></a></td>
|
<td><a href="/{{ list[i].avatar }}"><img class="avatar" src="/t/{{ list[i].avatar }}.webp"></a></td>
|
||||||
<td><a href="/user/{!! list[i].user !!}">{!! list[i].user !!}</a></td>
|
<td>@if(list[i].admin)⭐ @endif<a href="/user/{!! list[i].user !!}">{!! list[i].user !!}</a></td>
|
||||||
<td>{{ list[i].count }}</td>
|
<td>{{ list[i].count }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endfor
|
@endfor
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
@include(snippets/header)
|
@include(snippets/header)
|
||||||
<div id="main">
|
<div id="main">
|
||||||
<h1>Settings</h1>
|
<h1>Settings</h1>
|
||||||
@if(session.avatar)<a href="/{{ session.avatar }}"><img id="img_avatar" src="/t/{{ session.avatar }}.webp" /></a>@endif
|
@if(session.avatar)<a href="/{{ session.avatar }}"><img id="img_avatar" src="/t/{{ session.avatar }}.webp"></a>@endif
|
||||||
<h2>Account</h2>
|
<h2>Account</h2>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -10,8 +10,8 @@
|
||||||
<td>{{ session.id }}</td>
|
<td>{{ session.id }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>level</td>
|
<td>admin</td>
|
||||||
<td>{{ session.level }}/100</td>
|
<td>{{ !!session.admin }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>username</td>
|
<td>username</td>
|
||||||
|
@ -19,7 +19,14 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>avatar</td>
|
<td>avatar</td>
|
||||||
<td><input type="text" class="input" name="i_avatar" value="{{ session.avatar }}" /><input type="submit" id="s_avatar" value="save" /></td>
|
<td><input type="text" class="input" name="i_avatar" value="{{ session.avatar }}"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>mail</td>
|
||||||
|
<td><input type="text" class="input" name="i_mail" placeholder="hashed" disabled></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><input type="submit" id="s_avatar" value="save"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link user" href="#" content="{{ session.user }}" data-toggle="dropdown">
|
<a class="nav-link user" href="#" content="{{ session.user }}" data-toggle="dropdown">
|
||||||
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar" /><span>{{ session.user }}</span>
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar"><span>@if(session.admin)⭐ @endif{{ session.user }}</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a href="/user/{{ session.user.toLowerCase() }}">my profile</a></li>
|
<li><a href="/user/{{ session.user.toLowerCase() }}">my profile</a></li>
|
||||||
<li><a href="/user/{{ session.user.toLowerCase() }}/f0cks">my f0cks</a></li>
|
<li><a href="/user/{{ session.user.toLowerCase() }}/f0cks">my f0cks</a></li>
|
||||||
<li><a href="/user/{{ session.user.toLowerCase() }}/favs">my favs</a></li>
|
<li><a href="/user/{{ session.user.toLowerCase() }}/favs">my favs</a></li>
|
||||||
<li><a href="/search">search</a></li>
|
<li><a href="/search">search</a></li>
|
||||||
<li><a href="/admin">Admin</a></li>
|
@if(session.admin)<li><a href="/admin">Admin</a></li>@endif
|
||||||
<li><a href="/about">About</a></li>
|
<li><a href="/about">About</a></li>
|
||||||
<li><a href="/ranking">ranking</a></li>
|
<li><a href="/ranking">ranking</a></li>
|
||||||
<li><a href="/settings">settings</a></li>
|
<li><a href="/settings">settings</a></li>
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
@if(session)
|
|
||||||
<nav class="navbar navbar-expand-lg">
|
|
||||||
<a class="navbar-brand" href="/"><span class="f0ck" width="" height="">F0CK</span></a>
|
|
||||||
<div class="navigation-links">
|
|
||||||
<ul class="navbar-nav">
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link" href="#" content="{{ session.user }}" data-toggle="dropdown">
|
|
||||||
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar" /><span>{{ session.user }}</span>
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a href="/admin">adminpanel</a></li>
|
|
||||||
<li><a href="/user/{{ session.user.toLowerCase() }}/f0cks">my f0cks</a></li>
|
|
||||||
<li><a href="/user/{{ session.user.toLowerCase() }}/favs">my favs</a></li>
|
|
||||||
<li><a href="/settings">settings</a></li>
|
|
||||||
<li><a href="/search">search</a></li>
|
|
||||||
<li><a href="/about">About</a></li>
|
|
||||||
<li><a href="/ranking">Ranking</a></li>
|
|
||||||
<li><a href="/logout">logout</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item dropdown" id="themes">
|
|
||||||
<a class="nav-link ddcontent" href="#" content="{{ theme }}" data-toggle="dropdown">Themes</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
@each(themes as t)
|
|
||||||
<li><a href="/theme/{{ t }}">{{ t }}</a></li>
|
|
||||||
@endeach
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link ddcontent" href="#"@if(tmp?.mime) content="{{ tmp?.mime }}" data-toggle="dropdown"@endif>Filter@if(!tmp?.mime) ▼@endif</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endif">All</a></li>
|
|
||||||
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifaudio">Audio</a></li>
|
|
||||||
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifvideo">Video</a></li>
|
|
||||||
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifimage">Image</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item @if(session)dropdown@endif">
|
|
||||||
<a class="nav-link ddcontent" href="#"@if(typeof session.mode !== "undefined") content="{{ modes[session.mode] ?? 'sfw' }}" data-toggle="dropdown"@endif>Mode</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
@for(let i = 0; i < modes.length; i++)
|
|
||||||
<li><a class="dropdown-item" href="/mode/{{ i }}">{{ modes[i] }}</a></li>
|
|
||||||
@endfor
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a id="random" class="nav-link" href="/random">
|
|
||||||
<span class="nav-link-identifier">Random</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="collapse navbar-collapse show" id="navbarSupportedContent">
|
|
||||||
<div class="pagination-container-fluid">
|
|
||||||
<div class="pagination-wrapper">
|
|
||||||
@if(typeof pagination !== "undefined")
|
|
||||||
<nav class="pagination">
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ pagination.start }}" class="page-item-1 btn start@if(!pagination.prev) disabled@endif">«</a>
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ pagination.prev }}" class="page-item-2 btn prev@if(!pagination.prev) disabled@endif">‹</a>
|
|
||||||
@each(pagination.cheat as i)
|
|
||||||
@if(i == pagination.page)
|
|
||||||
<span class="btn disabled">{{ i }}</span>
|
|
||||||
@else
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ i }}" class="pagination-int-item btn">{{ i }}</a>
|
|
||||||
@endif
|
|
||||||
@endeach
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ pagination.next }}" class="page-item-3 btn next@if(!pagination.next) disabled@endif">›</a>
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ pagination.end }}" class="page-item-4 btn start@if(!pagination.next) disabled@endif">»</a>
|
|
||||||
</nav>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
@else
|
|
||||||
<nav class="navbar navbar-expand-lg">
|
|
||||||
<a class="navbar-brand" href="/"><span class="f0ck" width="" height="">F0CK</span></a>
|
|
||||||
|
|
||||||
<div class="navigation-links-guest">
|
|
||||||
<ul class="navbar-nav-guests">
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link" href="/about" data-toggle="dropdown">About</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a href="/login">login</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item dropdown" id="themes">
|
|
||||||
<a class="nav-link ddcontent" href="#" content="{{ theme }}" data-toggle="dropdown">Themes</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
@each(themes as t)
|
|
||||||
<li><a href="/theme/{{ t }}">{{ t }}</a></li>
|
|
||||||
@endeach
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link ddcontent" href="#"@if(tmp?.mime) content="{{ tmp?.mime }}" data-toggle="dropdown"@endif>Filter@if(!tmp?.mime) ▼@endif</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endif">All</a></li>
|
|
||||||
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifaudio">Audio</a></li>
|
|
||||||
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifvideo">Video</a></li>
|
|
||||||
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifimage">Image</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a id="random" class="nav-link" href="/random">
|
|
||||||
<span class="nav-link-identifier">Random</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="collapse navbar-collapse show" id="navbarSupportedContent">
|
|
||||||
<div class="pagination-container-fluid">
|
|
||||||
<div class="pagination-wrapper">
|
|
||||||
@if(typeof pagination !== "undefined")
|
|
||||||
<nav class="pagination">
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ pagination.start }}" class="page-item-1 btn start@if(!pagination.prev) disabled@endif">«</a>
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ pagination.prev }}" class="page-item-2 btn prev@if(!pagination.prev) disabled@endif">‹</a>
|
|
||||||
@each(pagination.cheat as i)
|
|
||||||
@if(i == pagination.page)
|
|
||||||
<span class="btn disabled">{{ i }}</span>
|
|
||||||
@else
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ i }}" class="pagination-int-item btn">{{ i }}</a>
|
|
||||||
@endif
|
|
||||||
@endeach
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ pagination.next }}" class="page-item-3 btn next@if(!pagination.next) disabled@endif">›</a>
|
|
||||||
<a href="{{ link.main }}{{ link.path }}{{ pagination.end }}" class="page-item-4 btn start@if(!pagination.next) disabled@endif">»</a>
|
|
||||||
</nav>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
@endif
|
|
|
@ -8,7 +8,7 @@
|
||||||
@endif
|
@endif
|
||||||
<div class="layersoffear">
|
<div class="layersoffear">
|
||||||
<div class="profile_head_username">
|
<div class="profile_head_username">
|
||||||
<span>{{ user.user }}</span>
|
<span>@if(user.admin)⭐ @endif{{ user.user }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="profile_head_user_stats">
|
<div class="profile_head_user_stats">
|
||||||
ID: {{ user.user_id }} – Joined: {{ user.created_at }}
|
ID: {{ user.user_id }} – Joined: {{ user.created_at }}
|
||||||
|
@ -18,9 +18,9 @@
|
||||||
<div class="user_content_wrapper">
|
<div class="user_content_wrapper">
|
||||||
<div class="f0cks">
|
<div class="f0cks">
|
||||||
<div class="f0cks-header">
|
<div class="f0cks-header">
|
||||||
f0ck{{ count.f0cks == 1 ? '' : 's' }}: {{ count.f0cks }} <a href="{{ f0cks.link.main }}">view all</a>
|
f0ck{{ count.f0cks == 1 ? '' : 's' }}: {{ count.f0cks }} <a href="{{ f0cks.link?.main }}">view all</a>
|
||||||
</div>
|
</div>
|
||||||
@if('items' in f0cks)
|
@if(count.f0cks)
|
||||||
<div class="posts">
|
<div class="posts">
|
||||||
@each(f0cks.items as item)
|
@each(f0cks.items as item)
|
||||||
<a href="{{ f0cks.link.main }}{{ item.id }}" data-mime="{{ item.mime }}" data-mode="{{ item.tag_id ? ['','sfw','nsfw'][item.tag_id] : 'null' }}" style="background-image: url('/t/{{ item.id }}.webp')"><p></p></a>
|
<a href="{{ f0cks.link.main }}{{ item.id }}" data-mime="{{ item.mime }}" data-mode="{{ item.tag_id ? ['','sfw','nsfw'][item.tag_id] : 'null' }}" style="background-image: url('/t/{{ item.id }}.webp')"><p></p></a>
|
||||||
|
@ -32,9 +32,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="favs">
|
<div class="favs">
|
||||||
<div class="favs-header">
|
<div class="favs-header">
|
||||||
fav{{ count.favs == 1 ? '' : 's' }}: {{ count.favs }} <a href="{{ favs.link.main }}">view all</a>
|
fav{{ count.favs == 1 ? '' : 's' }}: {{ count.favs }} <a href="{{ favs.link?.main }}">view all</a>
|
||||||
</div>
|
</div>
|
||||||
@if('items' in favs)
|
@if(count.favs)
|
||||||
<div class="posts">
|
<div class="posts">
|
||||||
@each(favs.items as item)
|
@each(favs.items as item)
|
||||||
<a href="{{ favs.link.main }}{{ item.id }}" data-mime="{{ item.mime }}" data-mode="{{ item.tag_id ? ['','sfw','nsfw'][item.tag_id] : 'null' }}" style="background-image: url('/t/{{ item.id }}.webp')"><p></p></a>
|
<a href="{{ favs.link.main }}{{ item.id }}" data-mime="{{ item.mime }}" data-mode="{{ item.tag_id ? ['','sfw','nsfw'][item.tag_id] : 'null' }}" style="background-image: url('/t/{{ item.id }}.webp')"><p></p></a>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user