Compare commits
No commits in common. "4a1caac2285bbe02fcc207c2fcb667d5c1567055" and "757fb5b48d10526e2a475a0b4ff2ac1f76362eaf" have entirely different histories.
4a1caac228
...
757fb5b48d
26
package-lock.json
generated
26
package-lock.json
generated
|
@ -11,7 +11,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cuffeo": "^1.0.7-3",
|
"cuffeo": "^1.0.7-3",
|
||||||
"flumm-fetch": "^1.0.1",
|
"flumm-fetch": "^1.0.1",
|
||||||
"flummpress": "^2.0.5",
|
"flummpress": "^2.0.4",
|
||||||
"postgres": "^3.0.1"
|
"postgres": "^3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -40,14 +40,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/flummpress": {
|
"node_modules/flummpress": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/flummpress/-/flummpress-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/flummpress/-/flummpress-2.0.4.tgz",
|
||||||
"integrity": "sha512-C/8Im6OvoZw67q9DvYIXKjKr28zHYLJdH4DucQ6zpVbN1eWPySmxkJTURbkq3uEwABXLngXLifS6mjxAC++umQ=="
|
"integrity": "sha512-AuEf/VnfC9hWqw+/0aH+Y+c8UgZ6CX/wVN8RR8V9btvYhIzLTJzVlyC0oTg5yrqLMUGaL9y8YRBjg2hKbFm94A=="
|
||||||
},
|
},
|
||||||
"node_modules/postgres": {
|
"node_modules/postgres": {
|
||||||
"version": "3.1.0",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/postgres/-/postgres-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postgres/-/postgres-3.0.2.tgz",
|
||||||
"integrity": "sha512-yQbJtA7z6SsQuFiF01rmHlkG2gU5IEv9D/Pn2fu8Tz6x3/suNWZs4fIPd59rkL+dfVfhDqYQ7DU3YnUqzEDB5Q==",
|
"integrity": "sha512-sHkEGAnPVqRclh5oIr9S9e/VNX0/MUb2PgS9bl/0wnI8WrHhzMmxqq/fAkMZKUUrC3Lfa4qaNh1dyDPH4Q8V0w==",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
"url": "https://github.com/sponsors/porsager"
|
"url": "https://github.com/sponsors/porsager"
|
||||||
|
@ -77,14 +77,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flummpress": {
|
"flummpress": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/flummpress/-/flummpress-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/flummpress/-/flummpress-2.0.4.tgz",
|
||||||
"integrity": "sha512-C/8Im6OvoZw67q9DvYIXKjKr28zHYLJdH4DucQ6zpVbN1eWPySmxkJTURbkq3uEwABXLngXLifS6mjxAC++umQ=="
|
"integrity": "sha512-AuEf/VnfC9hWqw+/0aH+Y+c8UgZ6CX/wVN8RR8V9btvYhIzLTJzVlyC0oTg5yrqLMUGaL9y8YRBjg2hKbFm94A=="
|
||||||
},
|
},
|
||||||
"postgres": {
|
"postgres": {
|
||||||
"version": "3.1.0",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/postgres/-/postgres-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/postgres/-/postgres-3.0.2.tgz",
|
||||||
"integrity": "sha512-yQbJtA7z6SsQuFiF01rmHlkG2gU5IEv9D/Pn2fu8Tz6x3/suNWZs4fIPd59rkL+dfVfhDqYQ7DU3YnUqzEDB5Q=="
|
"integrity": "sha512-sHkEGAnPVqRclh5oIr9S9e/VNX0/MUb2PgS9bl/0wnI8WrHhzMmxqq/fAkMZKUUrC3Lfa4qaNh1dyDPH4Q8V0w=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cuffeo": "^1.0.7-3",
|
"cuffeo": "^1.0.7-3",
|
||||||
"flumm-fetch": "^1.0.1",
|
"flumm-fetch": "^1.0.1",
|
||||||
"flummpress": "^2.0.5",
|
"flummpress": "^2.0.4",
|
||||||
"postgres": "^3.0.1"
|
"postgres": "^3.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,6 @@ html[theme='f0ck'] {
|
||||||
--scroller-bg: #424242;
|
--scroller-bg: #424242;
|
||||||
}
|
}
|
||||||
|
|
||||||
html[theme="f0ck"] .admin-search button {
|
|
||||||
color: var(--black)!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme='p1nk'] {
|
html[theme='p1nk'] {
|
||||||
--accent: #ff00d0;
|
--accent: #ff00d0;
|
||||||
--bg: #171717;
|
--bg: #171717;
|
||||||
|
@ -150,23 +146,6 @@ html[theme='amoled'] {
|
||||||
--scroller-bg: #424242;
|
--scroller-bg: #424242;
|
||||||
}
|
}
|
||||||
|
|
||||||
html[theme="amoled"] .admin-search button {
|
|
||||||
color: var(--black)!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme="amoled"] table.table tbody tr:nth-of-type(2n+1) a {
|
|
||||||
color: var(--white) !important;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme="amoled"] table.table tbody tr:nth-of-type(2n+1) {
|
|
||||||
color: var(--white) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme="amoled"] table.table a {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme="paper"] {
|
html[theme="paper"] {
|
||||||
--accent: #000;
|
--accent: #000;
|
||||||
--bg: #fff;
|
--bg: #fff;
|
||||||
|
@ -286,28 +265,6 @@ html[theme="paper"] span#favs {
|
||||||
border: 1px solid var(--white);
|
border: 1px solid var(--white);
|
||||||
}
|
}
|
||||||
|
|
||||||
html[theme="paper"] .admin-search button {
|
|
||||||
color: var(--white)!important;
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme="paper"] table.table tbody tr:nth-of-type(2n+1) a {
|
|
||||||
color: var(--white) !important;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme="paper"] table.table tbody tr:nth-of-type(2n+1) {
|
|
||||||
color: var(--white) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme="paper"] table.table a {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme="paper"] a {
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
html[theme="atmos"] {
|
html[theme="atmos"] {
|
||||||
--accent: #1fb2b0;
|
--accent: #1fb2b0;
|
||||||
--bg: #161618;
|
--bg: #161618;
|
||||||
|
@ -481,7 +438,7 @@ html, body {
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--accent) /* !important */;
|
color: var(--accent) !important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
@ -659,7 +616,7 @@ span.f0ck {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-image: linear-gradient(to bottom,var(--nav-link-background-linear-gradient));
|
background-image: linear-gradient(to bottom,var(--nav-link-background-linear-gradient));
|
||||||
box-shadow: var(--nav-link-box-shadow);
|
box-shadow: var(--nav-link-box-shadow);
|
||||||
/* color: transparent; */
|
color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-expand-lg .navbar-nav .nav-link, .pagination > a, .pagination > span {
|
.navbar-expand-lg .navbar-nav .nav-link, .pagination > a, .pagination > span {
|
||||||
|
@ -753,7 +710,6 @@ span.f0ck {
|
||||||
span.placeholder {
|
span.placeholder {
|
||||||
border-left: 1px solid var(--accent);
|
border-left: 1px solid var(--accent);
|
||||||
margin-left: 7px;
|
margin-left: 7px;
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar .nav-item .dropdown-menu {
|
.navbar .nav-item .dropdown-menu {
|
||||||
|
@ -1749,36 +1705,3 @@ a[data-mime^="audio"] {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Admin search css early test */
|
|
||||||
.admin-search {
|
|
||||||
margin-top: 15px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-search button {
|
|
||||||
background: var(--accent);
|
|
||||||
border: none;
|
|
||||||
color: var(--white);
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-search button:hover {
|
|
||||||
transition: .2s all;
|
|
||||||
opacity: 0.7;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-search input {
|
|
||||||
padding: 15px;
|
|
||||||
border: 1px solid var(--accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
table img {
|
|
||||||
border: 1px solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
.results {
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -249,7 +249,7 @@ const flash = ({ type, msg }) => {
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = `/user/${f.user}/favs`;
|
a.href = `/user/${f.user}/favs`;
|
||||||
a.setAttribute('tooltip', f.user);
|
a.setAttribute('tooltip', f.user);
|
||||||
a.setAttribute('flow', 'up');
|
a.setAttribute('flow', 'down');
|
||||||
|
|
||||||
const img = document.createElement('img');
|
const img = document.createElement('img');
|
||||||
img.src = `/t/${f.avatar}.webp`;
|
img.src = `/t/${f.avatar}.webp`;
|
||||||
|
|
|
@ -227,7 +227,6 @@ export default {
|
||||||
? db`group by st.tag, st.item_id, "items".id`
|
? db`group by st.tag, st.item_id, "items".id`
|
||||||
: db`group by "items".id, "favorites".user_id, "favorites".item_id, "user".id`
|
: db`group by "items".id, "favorites".user_id, "favorites".item_id, "user".id`
|
||||||
}
|
}
|
||||||
order by "items".id desc
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import db from "../sql.mjs";
|
import db from "../sql.mjs";
|
||||||
import lib from "../lib.mjs";
|
import lib from "../lib.mjs";
|
||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
|
import search from "../routeinc/search.mjs";
|
||||||
|
|
||||||
const auth = async (req, res, next) => {
|
const auth = async (req, res, next) => {
|
||||||
if(!req.session) {
|
if(!req.session) {
|
||||||
|
@ -119,6 +120,43 @@ export default (router, tpl) => {
|
||||||
}, req)
|
}, req)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get(/^\/admin\/test(\/)?$/, auth, async (req, res) => {
|
||||||
|
let ret;
|
||||||
|
if(Object.keys(req.url.qs).length > 0) {
|
||||||
|
let tag = req.url.qs.tag;
|
||||||
|
let rows;
|
||||||
|
|
||||||
|
if(tag.startsWith('src:')) {
|
||||||
|
tag = tag.substring(4);
|
||||||
|
ret = await db`
|
||||||
|
select *
|
||||||
|
from "items"
|
||||||
|
where src ilike ${'%' + tag + '%'}
|
||||||
|
limit 500
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rows = await db`
|
||||||
|
select "items".id, "items".username, "tags".tag
|
||||||
|
from "tags"
|
||||||
|
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
||||||
|
left join "items" on "items".id = "tags_assign".item_id
|
||||||
|
where "tags".tag ilike ${'%' + tag + '%'}
|
||||||
|
limit 500
|
||||||
|
`;
|
||||||
|
ret = search(rows, tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.reply({
|
||||||
|
body: tpl.render("admin/search", {
|
||||||
|
result: ret,
|
||||||
|
totals: await lib.countf0cks(),
|
||||||
|
session: req.session
|
||||||
|
}, req)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
router.get(/^\/admin\/log(\/)?$/, auth, async (req, res) => {
|
router.get(/^\/admin\/log(\/)?$/, auth, async (req, res) => {
|
||||||
exec("journalctl -qeu f0ck --no-pager", (err, stdout) => {
|
exec("journalctl -qeu f0ck --no-pager", (err, stdout) => {
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
import db from "../sql.mjs";
|
|
||||||
import lib from "../lib.mjs";
|
|
||||||
import search from "../routeinc/search.mjs";
|
|
||||||
|
|
||||||
export default (router, tpl) => {
|
|
||||||
router.get(/^\/search(\/)?$/, lib.auth, async (req, res) => {
|
|
||||||
let ret;
|
|
||||||
let tag = req.url.qs?.tag;
|
|
||||||
if(Object.keys(req.url.qs).length > 0) {
|
|
||||||
let rows;
|
|
||||||
|
|
||||||
if(tag.startsWith('src:')) {
|
|
||||||
tag = tag.substring(4);
|
|
||||||
ret = await db`
|
|
||||||
select *
|
|
||||||
from "items"
|
|
||||||
where src ilike ${'%' + tag + '%'}
|
|
||||||
limit 500
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rows = await db`
|
|
||||||
select "items".id, "items".username, "items".mime, "tags".tag
|
|
||||||
from "tags"
|
|
||||||
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
|
||||||
left join "items" on "items".id = "tags_assign".item_id
|
|
||||||
where "tags".tag ilike ${'%' + tag + '%'}
|
|
||||||
limit 500
|
|
||||||
`;
|
|
||||||
ret = search(rows, tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res.reply({
|
|
||||||
body: tpl.render("search", {
|
|
||||||
result: ret,
|
|
||||||
totals: await lib.countf0cks(),
|
|
||||||
searchstring: tag,
|
|
||||||
session: req.session,
|
|
||||||
tmp: null
|
|
||||||
}, req)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
27
views/admin/search.html
Normal file
27
views/admin/search.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
@include(snippets/header_admin)
|
||||||
|
<form action="/admin/test" style="margin-top: 15px;">
|
||||||
|
<input type="text" name="tag" /><button type="submit">search</button>
|
||||||
|
</form>
|
||||||
|
<hr />
|
||||||
|
@if(result)
|
||||||
|
<h1>{{ result.length }} f0cks given</h1>
|
||||||
|
<table style="width: 100%;">
|
||||||
|
<tr>
|
||||||
|
<td style="text-align: center;">Thumbnail</td>
|
||||||
|
<td style="text-align: center;">ID</td>
|
||||||
|
<td style="text-align: center;">Tag</td>
|
||||||
|
<td style="text-align: center;">Username</td>
|
||||||
|
<td style="text-align: center;">Score</td>
|
||||||
|
</tr>
|
||||||
|
@each(result as line)
|
||||||
|
<tr>
|
||||||
|
<td style="width: 128px;"><a href="/{{ line.id }}" target="_blank"><img src="/t/{{ line.id }}.webp" /></a></td>
|
||||||
|
<td style="text-align: center;"><a href="/{{ line.id }}" target="_blank">{{ line.id }}</a></td>
|
||||||
|
<td style="text-align: center;"><a href="/admin/test?tag={{ line.tag?.replace(/\s/g, "+") }}">{{ line.tag }}</a></td>
|
||||||
|
<td style="text-align: center;">{{ line.username }}</td>
|
||||||
|
<td style="text-align: center;">{{ line.score }}</td>
|
||||||
|
</tr>
|
||||||
|
@endeach
|
||||||
|
</table>
|
||||||
|
@endif
|
||||||
|
@include(snippets/footer)
|
|
@ -79,7 +79,7 @@
|
||||||
<span class="badge" id="favs"@if(!item.favorites.length || !session) hidden@endif>
|
<span class="badge" id="favs"@if(!item.favorites.length || !session) hidden@endif>
|
||||||
@if(item.favorites.length && session)
|
@if(item.favorites.length && session)
|
||||||
@each(item.favorites as fav)
|
@each(item.favorites as fav)
|
||||||
<a href="/user/{{ fav.user.toLowerCase() }}/favs" tooltip="{{ fav.user }}" flow="up"><img src="@if(fav.avatar)/t/{{ fav.avatar }}.webp@else/s/img/default.png@endif" style="height: 32px; width: 32px" /></a>
|
<a href="/user/{{ fav.user.toLowerCase() }}/favs" tooltip="{{ fav.user }}" flow="down"><img src="@if(fav.avatar)/t/{{ fav.avatar }}.webp@else/s/img/default.png@endif" style="height: 32px; width: 32px" /></a>
|
||||||
@endeach
|
@endeach
|
||||||
@endif
|
@endif
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -10,8 +10,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><img class="avatar" src="/t/{{ list[i].avatar }}.webp" /></td>
|
||||||
<td><a href="/user/{!! list[i].user !!}">{!! list[i].user !!}</a></td>
|
<td>{!! list[i].user !!}</td>
|
||||||
<td>{{ list[i].count }}</td>
|
<td>{{ list[i].count }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endfor
|
@endfor
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
@include(snippets/header)
|
|
||||||
<h1 style="text-align: center">f0ckgle</h1>
|
|
||||||
<form action="/search" class="admin-search">
|
|
||||||
<input type="text" name="tag" value="{!! searchstring !!}" /><button type="submit"><b>f0ck</b></button>
|
|
||||||
</form>
|
|
||||||
<div class="results">
|
|
||||||
@if(result)
|
|
||||||
<h1>{{ result.length }} f0cks given:</h1>
|
|
||||||
<table style="width: 100%;" class="table">
|
|
||||||
<tr>
|
|
||||||
<th>Thumbnail</th>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Tag</th>
|
|
||||||
<th>Mime</th>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>Score</th>
|
|
||||||
</tr>
|
|
||||||
@each(result as line)
|
|
||||||
<tr>
|
|
||||||
<td style="width: 128px;"><a href="/tag/{!! line.tag !!}/{{ line.id }}" target="_blank"><img src="/t/{{ line.id }}.webp" /></a></td>
|
|
||||||
<td style="text-align: center;"><a href="/tag/{!! line.tag !!}/{{ line.id }}" target="_blank">{{ line.id }}</a></td>
|
|
||||||
<td style="text-align: center;"><a href="/tag/{!! line.tag !!}">{!! line.tag !!}</a></td>
|
|
||||||
<td style="text-align: center;">{{ line.mime }}</td>
|
|
||||||
<td style="text-align: center;"><a href="/user/{!! line.username !!}/f0cks/{{ line.id }}">{!! line.username !!}</a></td>
|
|
||||||
<td style="text-align: center;">{{ line.score.toFixed(2) }}</td>
|
|
||||||
</tr>
|
|
||||||
@endeach
|
|
||||||
</table>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
@include(snippets/footer)
|
|
|
@ -12,7 +12,6 @@
|
||||||
<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="/settings">settings</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="/about">About</a></li>
|
||||||
<li><a href="/ranking">Ranking</a></li>
|
<li><a href="/ranking">Ranking</a></li>
|
||||||
<li><a href="/logout">logout</a></li>
|
<li><a href="/logout">logout</a></li>
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
<span class="nav-link-identifier">sessions</span>
|
<span class="nav-link-identifier">sessions</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/admin/test">
|
||||||
|
<span class="nav-link-identifier">search (wip)</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/admin/log">
|
<a class="nav-link" href="/admin/log">
|
||||||
<span class="nav-link-identifier">Log</span>
|
<span class="nav-link-identifier">Log</span>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user