Compare commits
4 Commits
83d3621441
...
0a92586c53
| Author | SHA1 | Date |
|---|---|---|
|
|
0a92586c53 | |
|
|
90b3d8a4d6 | |
|
|
5a2e93e900 | |
|
|
4e81a8a1d6 |
|
|
@ -1,22 +1,21 @@
|
|||
<template>
|
||||
<div class="warning-container">
|
||||
<div class="warning">
|
||||
<div
|
||||
class="logo"
|
||||
v-html="logo"
|
||||
/>
|
||||
|
||||
<strong class="title">This website contains sexually explicit content</strong>
|
||||
|
||||
<span class="copy agree">By entering, you agree to the following</span>
|
||||
<strong class="title">
|
||||
<div
|
||||
class="logo"
|
||||
v-html="logo"
|
||||
/>contains sexually explicit content
|
||||
</strong>
|
||||
|
||||
<ul class="rules">
|
||||
<li class="rule">You are at least 18 years old, and legally permitted to view adult material in your jurisdiction.</li>
|
||||
<li class="rule">You are prepared see, hear and read erotic and sexual material, and do not regard such content as obscene or offensive.</li>
|
||||
<li class="rule">You do not regard erotic, sexual and pornographic material as obscene or offensive.</li>
|
||||
<li class="rule">You understand that most sexual scenarios depicted on this website are fictional, performed by professional actors for the purpose of entertainment, and not representative of real-life interactions.</li>
|
||||
<li class="rule">Respect your sexual partners, communicate about each other's desires and limits, and take precautions to prevent sexually transmitted infections and unintended pregnancies.</li>
|
||||
</ul>
|
||||
|
||||
<span class="preferences">You can adjust your content preferences later</span>
|
||||
|
||||
<div class="actions">
|
||||
<a
|
||||
href="https://www.google.com"
|
||||
|
|
@ -40,8 +39,6 @@
|
|||
<span class="button-sub">I prefer straight content</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<span class="preferences">You can adjust your content preferences later</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -84,21 +81,22 @@ export default {
|
|||
|
||||
.logo {
|
||||
width: 8rem;
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
fill: var(--primary);
|
||||
margin: 1rem auto 0 auto;
|
||||
margin: -.125rem .5rem 0 0;
|
||||
}
|
||||
|
||||
.title,
|
||||
.copy,
|
||||
.rules {
|
||||
padding: 1rem;
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: block;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 2rem;
|
||||
margin: 0 0 1rem 0;
|
||||
margin: 1rem 0 0 0;
|
||||
color: var(--text-light);
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +201,7 @@ export default {
|
|||
.preferences {
|
||||
color: var(--lighten);
|
||||
display: block;
|
||||
padding: .5rem 0 2rem 0;
|
||||
padding: .5rem 0 1rem 0;
|
||||
text-align: center;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@
|
|||
v-else-if="release.teaser && /^image\//.test(release.teaser.mime)"
|
||||
:src="getPath(release.teaser, 'thumbnail', { original: true })"
|
||||
:alt="release.title"
|
||||
:width="photo.width"
|
||||
:height="photo.height"
|
||||
:width="release.teaser.width"
|
||||
:height="release.teaser.height"
|
||||
loading="lazy"
|
||||
class="item trailer"
|
||||
>
|
||||
|
|
@ -68,8 +68,8 @@
|
|||
<img
|
||||
:src="getPath(cover, 'thumbnail')"
|
||||
:style="{ 'background-image': getBgPath(cover, 'lazy') }"
|
||||
:width="photo.width"
|
||||
:height="photo.height"
|
||||
:width="cover.width"
|
||||
:height="cover.height"
|
||||
class="item cover"
|
||||
loading="lazy"
|
||||
@load="$emit('load', $event)"
|
||||
|
|
|
|||
|
|
@ -55,14 +55,14 @@
|
|||
v-show="me && isStashed"
|
||||
icon="heart7"
|
||||
class="stash stashed noselect"
|
||||
@click="unstashScene"
|
||||
@click="unstashRelease"
|
||||
/>
|
||||
|
||||
<Icon
|
||||
v-show="me && !isStashed"
|
||||
icon="heart8"
|
||||
class="stash unstashed noselect"
|
||||
@click="stashScene"
|
||||
@click="stashRelease"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -251,18 +251,20 @@ async function fetchRelease(scroll = true) {
|
|||
}
|
||||
}
|
||||
|
||||
async function stashScene() {
|
||||
this.$store.dispatch('stashScene', {
|
||||
async function stashRelease() {
|
||||
this.$store.dispatch(this.$route.name === 'movie' ? 'stashMovie' : 'stashRelease', {
|
||||
sceneId: this.release.id,
|
||||
movieId: this.release.id,
|
||||
stashId: this.$store.getters.favorites.id,
|
||||
});
|
||||
|
||||
this.fetchRelease(false);
|
||||
}
|
||||
|
||||
async function unstashScene() {
|
||||
this.$store.dispatch('unstashScene', {
|
||||
async function unstashRelease() {
|
||||
this.$store.dispatch(this.$route.name === 'movie' ? 'unstashMovie' : 'unstashRelease', {
|
||||
sceneId: this.release.id,
|
||||
movieId: this.release.id,
|
||||
stashId: this.$store.getters.favorites.id,
|
||||
});
|
||||
|
||||
|
|
@ -321,8 +323,8 @@ export default {
|
|||
mounted: fetchRelease,
|
||||
methods: {
|
||||
fetchRelease,
|
||||
stashScene,
|
||||
unstashScene,
|
||||
stashRelease,
|
||||
unstashRelease,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -164,12 +164,16 @@ export default {
|
|||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: .05rem .25rem .1rem .15rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
box-sizing: border-box;
|
||||
padding: .1rem;
|
||||
border-radius: 0 0 .5rem 0;
|
||||
color: var(--text-light);
|
||||
background: var(--primary);
|
||||
font-size: .8rem;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -372,7 +376,6 @@ export default {
|
|||
.tile.new .poster::after {
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
padding: .1rem .25rem .05rem .15rem;
|
||||
border-radius: 0 .5rem 0 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,11 @@ function initReleasesActions(store, router) {
|
|||
// const release = await get(`/releases/${releaseId}`);
|
||||
|
||||
const { movie } = await graphql(`
|
||||
query Movie($movieId: Int!) {
|
||||
query Movie(
|
||||
$movieId: Int!
|
||||
$hasAuth: Boolean!
|
||||
$userId: Int
|
||||
) {
|
||||
movie(id: $movieId) {
|
||||
id
|
||||
title
|
||||
|
|
@ -232,10 +236,27 @@ function initReleasesActions(store, router) {
|
|||
hasLogo
|
||||
}
|
||||
}
|
||||
stashes: stashesMovies(
|
||||
filter: {
|
||||
stash: {
|
||||
userId: {
|
||||
equalTo: $userId
|
||||
}
|
||||
}
|
||||
}
|
||||
) @include(if: $hasAuth) {
|
||||
stash {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`, {
|
||||
movieId: Number(movieId),
|
||||
hasAuth: !!store.state.auth.user,
|
||||
userId: store.state.auth.user?.id,
|
||||
});
|
||||
|
||||
if (!movie) {
|
||||
|
|
|
|||
|
|
@ -17,11 +17,21 @@ function initStashesActions(_store, _router) {
|
|||
await del(`/stashes/${stashId}/scenes/${sceneId}`);
|
||||
}
|
||||
|
||||
async function stashMovie(context, { movieId, stashId }) {
|
||||
await post(`/stashes/${stashId}/movies`, { movieId });
|
||||
}
|
||||
|
||||
async function unstashMovie(context, { movieId, stashId }) {
|
||||
await del(`/stashes/${stashId}/movies/${movieId}`);
|
||||
}
|
||||
|
||||
return {
|
||||
stashActor,
|
||||
stashScene,
|
||||
stashMovie,
|
||||
unstashActor,
|
||||
unstashScene,
|
||||
unstashMovie,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1054,7 +1054,8 @@ exports.up = knex => Promise.resolve()
|
|||
|
||||
table.integer('user_id')
|
||||
.references('id')
|
||||
.inTable('users');
|
||||
.inTable('users')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.string('name')
|
||||
.notNullable();
|
||||
|
|
@ -1074,27 +1075,48 @@ exports.up = knex => Promise.resolve()
|
|||
table.integer('stash_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('stashes');
|
||||
.inTable('stashes')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('scene_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('releases');
|
||||
.inTable('releases')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique(['stash_id', 'scene_id']);
|
||||
|
||||
table.string('comment');
|
||||
}))
|
||||
.then(() => knex.schema.createTable('stashes_movies', (table) => {
|
||||
table.integer('stash_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('stashes')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('movie_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('movies')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique(['stash_id', 'movie_id']);
|
||||
|
||||
table.string('comment');
|
||||
}))
|
||||
.then(() => knex.schema.createTable('stashes_actors', (table) => {
|
||||
table.integer('stash_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('stashes');
|
||||
.inTable('stashes')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('actor_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('actors');
|
||||
.inTable('actors')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique(['stash_id', 'actor_id']);
|
||||
|
||||
|
|
@ -1304,6 +1326,7 @@ exports.up = knex => Promise.resolve()
|
|||
|
||||
ALTER TABLE stashes ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE stashes_scenes ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE stashes_movies ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE stashes_actors ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY stashes_policy_select ON stashes FOR SELECT USING (stashes.public OR stashes.user_id = current_user_id());
|
||||
|
|
@ -1319,6 +1342,14 @@ exports.up = knex => Promise.resolve()
|
|||
AND (stashes.user_id = current_user_id() OR stashes.public)
|
||||
));
|
||||
|
||||
CREATE POLICY stashes_policy ON stashes_movies
|
||||
USING (EXISTS (
|
||||
SELECT *
|
||||
FROM stashes
|
||||
WHERE stashes.id = stashes_movies.stash_id
|
||||
AND (stashes.user_id = current_user_id() OR stashes.public)
|
||||
));
|
||||
|
||||
CREATE POLICY stashes_policy ON stashes_actors
|
||||
USING (EXISTS (
|
||||
SELECT *
|
||||
|
|
@ -1416,6 +1447,7 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style
|
|||
DROP TABLE IF EXISTS entities CASCADE;
|
||||
|
||||
DROP TABLE IF EXISTS stashes_scenes CASCADE;
|
||||
DROP TABLE IF EXISTS stashes_movies CASCADE;
|
||||
DROP TABLE IF EXISTS stashes_actors CASCADE;
|
||||
DROP TABLE IF EXISTS stashes CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "traxxx",
|
||||
"version": "1.186.0",
|
||||
"version": "1.186.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "1.186.0",
|
||||
"version": "1.186.1",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@casl/ability": "^5.2.2",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "traxxx",
|
||||
"version": "1.186.0",
|
||||
"version": "1.186.1",
|
||||
"description": "All the latest porn releases in one place",
|
||||
"main": "src/app.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 3.0 MiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 3.2 MiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 3.1 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 2.7 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 495 KiB After Width: | Height: | Size: 495 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
|
@ -98,7 +98,7 @@ const tags = [
|
|||
{
|
||||
name: 'airtight',
|
||||
slug: 'airtight',
|
||||
description: 'Stuffing one cock in her ass, one in her pussy, and one in her mouth, filling all of her penetrable holes and sealing her airtight like a figurative balloon. In other words, simultaneously getting [double penetrated](/tag/dp), and giving a [blowjob](/tag/blowjob) or getting [facefucked](/tag/facefuck). Being airtight implies being [gangbanged](/tag/gangbang).', /* eslint-disable-line max-len */
|
||||
description: 'Stuffing one cock in your ass, one in your pussy, and one in your mouth, filling up all of your penetrable holes and getting sealed airtight like a figurative balloon. In other words, simultaneously getting [double penetrated](/tag/dp), and giving a [blowjob](/tag/blowjob) or getting [facefucked](/tag/facefucking). Being airtight implies being [gangbanged](/tag/gangbang).', /* eslint-disable-line max-len */
|
||||
priority: 9,
|
||||
group: 'penetration',
|
||||
},
|
||||
|
|
@ -116,19 +116,19 @@ const tags = [
|
|||
{
|
||||
name: 'anal',
|
||||
slug: 'anal',
|
||||
description: 'Getting fucked in the asshole.',
|
||||
description: 'Getting your asshole fucked. Generally considered naughtier, you may or may not find it a pleasurable alternative to vaginal sex. Enjoyable anal sex tends to require practice and patience, a rectal douching ritual, as well and a generous use of water-based lubricant to ensure comfort and prevent small tears that could lead to bacterial infections. Although you cannot get pregnant through anal sex directly, there is an increased risk of passing STDs, so the use of condoms and regular health checks are strongly recommended.',
|
||||
priority: 9,
|
||||
group: 'penetration',
|
||||
},
|
||||
{
|
||||
name: 'anal fingering',
|
||||
slug: 'anal-fingering',
|
||||
description: 'Inserting one or multiple fingers into the asshole.',
|
||||
description: 'Inserting one or multiple fingers into your asshole. If you use your entire hand beyond the knuckles, you are [anal fisting](/tag/anal-fisting).',
|
||||
},
|
||||
{
|
||||
name: 'anal fisting',
|
||||
slug: 'anal-fisting',
|
||||
description: 'Shoving an entire hand into the asshole.',
|
||||
description: 'Shoving an entire hand into your asshole.',
|
||||
},
|
||||
{
|
||||
name: 'anal prolapse',
|
||||
|
|
@ -242,13 +242,14 @@ const tags = [
|
|||
name: 'blowjob',
|
||||
slug: 'blowjob',
|
||||
priority: 5,
|
||||
description: 'Taking a dick in your mouth, sucking, licking and kissing it, often while giving a [handjob](/tag/handjob). You may slide it all the way [down your throat](/tag/deepthroat), or let them [fuck your face](/tag/facefucking).',
|
||||
group: 'oral',
|
||||
},
|
||||
{
|
||||
name: 'blowbang',
|
||||
slug: 'blowbang',
|
||||
priority: 9,
|
||||
description: 'Pleasuring a gang of three or more cocks by sucking and jerking off as many cocks as they can, often getting [facefucked](/tag/facefuck), groped and rubbed out, and followed by a [bukkake](/tag/bukkake). If they are getting fucked, it is a [gangbang](/tag/gangbang).',
|
||||
description: 'Pleasuring a gang of three or more cocks by sucking and jerking off as many cocks as you can, often getting [facefucked](/tag/facefucking), groped and rubbed out, and followed by a [bukkake](/tag/bukkake). If you are also getting fucked, it is a [gangbang](/tag/gangbang).',
|
||||
group: 'group',
|
||||
},
|
||||
{
|
||||
|
|
@ -343,7 +344,7 @@ const tags = [
|
|||
{
|
||||
name: 'double anal',
|
||||
slug: 'dap',
|
||||
description: 'Two cocks in the ass at the same time. If there\'s a third cock in her pussy, it is [double anal TP](/tag/da-tp).',
|
||||
description: 'Two cocks filling up your ass at the same time. If there\'s a third cock in your pussy, it is [double anal triple penetration](/tag/da-tp).',
|
||||
priority: 8,
|
||||
group: 'penetration',
|
||||
},
|
||||
|
|
@ -388,13 +389,14 @@ const tags = [
|
|||
name: 'deepthroat',
|
||||
slug: 'deepthroat',
|
||||
priority: 6,
|
||||
description: 'Shoving a cock down your throat during a [blowjob](/tag/blowjob) or [facefuck](/tag/facefucking), giving them a tight sensation while showing off your skills. Without practice, a cock hitting the back of your mouth will likely make you [gag](/tag/gagging).',
|
||||
group: 'oral',
|
||||
},
|
||||
{
|
||||
name: 'double penetration',
|
||||
slug: 'dp',
|
||||
priority: 9,
|
||||
description: 'Fucking two cocks at once, with one in her ass, and one in her pussy. If she has another cock in her mouth, she is [airtight](/tag/airtight).',
|
||||
description: 'Getting your [ass](/tag/anal) and pussy fucked at the same time. If you take another cock in your mouth, you are [airtight](/tag/airtight).',
|
||||
group: 'penetration',
|
||||
},
|
||||
{
|
||||
|
|
@ -404,7 +406,7 @@ const tags = [
|
|||
{
|
||||
name: 'double vaginal',
|
||||
slug: 'dvp',
|
||||
description: 'Fucking her pussy with two cocks at the same time. If there\'s a third cock in her asshole, it is [double vaginal TP](/tag/dv-tp).',
|
||||
description: 'Getting fucked with two cocks in your pussy at the same time. If there\'s a third cock in your asshole, it is [double vaginal triple penetration](/tag/dv-tp).',
|
||||
priority: 8,
|
||||
group: 'penetration',
|
||||
},
|
||||
|
|
@ -450,6 +452,7 @@ const tags = [
|
|||
name: 'facefucking',
|
||||
slug: 'facefucking',
|
||||
priority: 7,
|
||||
description: 'A [blowjob](/tag/blowjob) where you give up control, and let them fuck your mouth and [throat](/tag/deepthroat) as if it\'s your pussy.',
|
||||
group: 'oral',
|
||||
},
|
||||
{
|
||||
|
|
@ -487,6 +490,10 @@ const tags = [
|
|||
name: 'fisting DP',
|
||||
slug: 'fisting-dp',
|
||||
},
|
||||
{
|
||||
name: 'flexible',
|
||||
slug: 'flexible',
|
||||
},
|
||||
{
|
||||
name: 'MFF threesome',
|
||||
slug: 'mff',
|
||||
|
|
@ -953,14 +960,14 @@ const tags = [
|
|||
name: 'DA triple penetration',
|
||||
slug: 'da-tp',
|
||||
priority: 7,
|
||||
description: 'Triple penetration with two cocks in the ass, and one in the pussy. Also see [double vaginal TP](/tag/dv-tp).',
|
||||
description: 'Triple penetration with [two cocks in your ass](/tag/dap), and one in your pussy. Also see [double vaginal triple penetration](/tag/dv-tp).',
|
||||
group: 'penetration',
|
||||
},
|
||||
{
|
||||
name: 'DV triple penetration',
|
||||
slug: 'dv-tp',
|
||||
priority: 7,
|
||||
description: 'Triple penetration with two cocks in the pussy, and one in the ass. Also see [double anal TP](/tag/da-tp).',
|
||||
description: 'Triple penetration with [two cocks in your pussy](/tag/dvp), and one in [your ass](/tag/anal). Also see [double anal triple penetration](/tag/da-tp).',
|
||||
group: 'penetration',
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -650,9 +650,10 @@ const tagMedia = [
|
|||
['blowbang', 1, 'Nicole Black in GIO1680', 'legalporno'],
|
||||
['blowjob', 1, 'Kylie Page in "Stepsis Gives Soapy Handjob In Shower"', 'spyfam'],
|
||||
['blowjob', 4, 'Chloe Cherry in "Chloe\'s Big Anal"', 'darkx'],
|
||||
['blowjob', 'cecilia_lion_wefuckblackgirls', 'Cecilia Lion in "Cecilia Lion\'s Second Appearance"', 'wefuckblackgirls'],
|
||||
['blowjob', 0, 'Adriana Chechik in "The Dinner Party"', 'realwifestories'],
|
||||
['blowjob', 5, 'Kaylynn', 'mommyblowsbest'],
|
||||
['blowjob', 'azul_hermosa_realitykings', 'Azul Hermosa and Scott Nails in "Diva For A Day"', 'brazzers'],
|
||||
['blowjob', 0, 'Adriana Chechik in "The Dinner Party"', 'realwifestories'],
|
||||
['blowjob', 3, 'Rose Valie', 'handsonhardcore'],
|
||||
['blowjob', 2, 'Luna Kitsuen in "Gag Reflex"', 'evilangel'],
|
||||
['bondage', 0, 'Veronica Leal', 'herlimit'],
|
||||
|
|
@ -675,6 +676,7 @@ const tagMedia = [
|
|||
['cum-in-mouth', 5, 'Emma Hix in "A Big Dick"', 'darkx'],
|
||||
['cum-in-mouth', 4, 'Vanna Bardot and Isiah Maxwell in "Vanna Craves Isiah\'s Cock!"', 'darkx'],
|
||||
['cum-in-mouth', 2, 'Jaye Summers in "Double The Cum"', 'hardx'],
|
||||
['cum-in-mouth', 'lara_frost_legalporno', 'Lara Frost in NRX059', 'legalporno'],
|
||||
['cum-in-mouth', 0, 'Vina Sky and Avi Love', 'hardx'],
|
||||
['cum-on-boobs', 1, 'Kylie Page in "Melt In Your Mouth"', 'twistyshard'],
|
||||
['cum-on-boobs', 0, 'Alessandra Jane', 'private'],
|
||||
|
|
@ -746,6 +748,7 @@ const tagMedia = [
|
|||
['dp', 3, 'Hime Marie in AA047', 'legalporno'],
|
||||
['dp', 2, 'Megan Rain in "DP Masters 4"', 'julesjordan'],
|
||||
['dp', 6, 'Kira Noir', 'hardx'],
|
||||
['dp', 'lara_frost_legalporno', 'Lara Frost in NRX070', 'legalporno'],
|
||||
['dp', 5, 'Lana Rhoades in "Gangbang Me 3"', 'hardx'],
|
||||
['dp', 'zaawaadi_roccosiffredi', 'Zaawaadi in "My Name Is Zaawaadi"', 'roccosiffredi'],
|
||||
['dp', 7, 'Chloe Lamour in "DP Masters 7"', 'julesjordan'],
|
||||
|
|
@ -771,6 +774,7 @@ const tagMedia = [
|
|||
['facial', 'hope_howell_manojob', 'Hope Howell in "Super Slutty Step-Daugher"', 'manojob'],
|
||||
['facial', 2, 'Ashly Anderson', 'hookuphotshot'],
|
||||
['facial', 4, 'Kendra Heart', 'facialsforever'],
|
||||
['flexible', 'lara_frost_legalporno', 'Lara Frost in NRX059', 'legalporno'],
|
||||
['enhanced-boobs', 7, 'Charley Atwell', 'icandigirls'],
|
||||
['enhanced-boobs', 14, 'Rikki Six', 'dreamdolls'],
|
||||
['enhanced-boobs', 2, 'Gia Milana in "Hot Anal Latina"', 'hardx'],
|
||||
|
|
@ -787,7 +791,8 @@ const tagMedia = [
|
|||
['enhanced-boobs', '23d', 'Lulu Sex Bomb in "Tropical Touch"'],
|
||||
['enhanced-boobs', 22, 'Sakura Sena'],
|
||||
['enhanced-boobs', 'mareeva_trudy_photodromm_1', 'Mareeva and Trudy', 'photodromm'],
|
||||
['enhanced-boobs', 'shawna_lenee_inthecrack_1', 'Shawna Lenee', 'inthecrack'],
|
||||
['enhanced-boobs', 'lara_frost_legalporno', 'Lara Frost in NRX059', 'legalporno'],
|
||||
['enhanced-boobs', 'shawna_lenee_inthecrack_3', 'Shawna Lenee', 'inthecrack'],
|
||||
['enhanced-boobs', 16, 'Marsha May in "Once You Go Black 7"', 'julesjordan'],
|
||||
['enhanced-boobs', 'azul_hermosa_pornstarslikeitbig', 'Azul Hermosa in "She Likes Rough Quickies"', 'pornstarslikeitbig'],
|
||||
['enhanced-boobs', 21, 'Emelie Ekström'],
|
||||
|
|
@ -814,10 +819,10 @@ const tagMedia = [
|
|||
['fisting', 0, 'Abella Danger and Karma Rx in "Neon Dreaming"', 'brazzers'],
|
||||
['fisting-dp', 0, 'Janice Griffith and Veronica Avluv in "The Nymphomaniac\'s Apprentice', 'theupperfloor'],
|
||||
['gangbang', 5, 'Carter Cruise\'s first gangbang in "Slut Puppies 9"', 'julesjordan'],
|
||||
['gangbang', 'poster', 'Kristen Scott in "Interracial Gangbang!"', 'julesjordan'],
|
||||
['gangbang', 7, 'Alexa Flexy in GL376'],
|
||||
['gangbang', 'kristen_scott_julesjordan', 'Kristen Scott in "Interracial Gangbang!"', 'julesjordan'],
|
||||
['gangbang', 'lara_frost_legalporno_1', 'Lara Frost in NRX070', 'legalporno'],
|
||||
['gangbang', 7, 'Alexa Flexy in GL376', 'legalporno'],
|
||||
['gangbang', 0, '"4 On 1 Gangbangs"', 'doghousedigital'],
|
||||
['gangbang', 6, 'Silvia Soprano in GIO1580', 'legalporno'],
|
||||
['gangbang', 4, 'Marley Brinx in "The Gangbang of Marley Brinx"', 'julesjordan'],
|
||||
['gangbang', 1, 'Ginger Lynn in "Gangbang Mystique", a photoset shot by Suze Randall, 1984. Depicting a woman \'airtight\' pushed the boundaries of pornography at the time.'],
|
||||
['gaping', 1, 'Vina Sky in "Vina Sky Does Anal"', 'hardx'],
|
||||
|
|
@ -914,8 +919,9 @@ const tagMedia = [
|
|||
['titty-fucking', 4, 'Set 5532', 'tugjobs'],
|
||||
['titty-fucking', 3, 'Anna Bell Peaks in "Ringing Her Bell"', 'milfvr'],
|
||||
['titty-fucking', 1, 'Chloe Lamour', 'ddfbusty'],
|
||||
['toy-anal', 1, 'Nina North and Cassidy Klein in "Nina\'s First Lesbian Anal"', 'lesbianx'],
|
||||
['toy-anal', 3, 'Kelly and Leona in "Sleeping Over"', 'lezcuties'],
|
||||
['toy-anal', 'ember_snow_jane_wilde_lesbianx', 'Ember Snow and Jane Wilde in "Ember\'s Wilde Ride"', 'lesbianx'],
|
||||
['toy-anal', 1, 'Nina North and Cassidy Klein in "Nina\'s First Lesbian Anal"', 'lesbianx'],
|
||||
['toy-anal', 2, 'Denise, Irina and Laki in "Sexy Slumber"', 'lezcuties'],
|
||||
['toy-anal', 0, 'Kira Noir in 1225', 'inthecrack'],
|
||||
['toy-dp', 1, 'Krissy Lynn and London River in "Lesbian DP Workout"', 'lesbianx'],
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ async function signup(credentials) {
|
|||
const hashedPassword = (await scrypt(credentials.password, salt, 64)).toString('hex');
|
||||
const storedPassword = `${salt}/${hashedPassword}`;
|
||||
|
||||
const [user] = await knex('users')
|
||||
const [userId] = await knex('users')
|
||||
.insert({
|
||||
username: credentials.username,
|
||||
email: credentials.email,
|
||||
|
|
@ -76,13 +76,13 @@ async function signup(credentials) {
|
|||
.returning('id');
|
||||
|
||||
await knex('stashes').insert({
|
||||
user_id: user.id,
|
||||
user_id: userId,
|
||||
name: 'Favorites',
|
||||
slug: 'favorites',
|
||||
public: false,
|
||||
});
|
||||
|
||||
return fetchUser(user.id);
|
||||
return fetchUser(userId);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@ const knex = require('./knex');
|
|||
const { HttpError } = require('./errors');
|
||||
|
||||
function curateStash(stash) {
|
||||
if (!stash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const curatedStash = {
|
||||
id: stash.id,
|
||||
name: stash.name,
|
||||
|
|
@ -52,12 +56,22 @@ async function stashScene(sceneId, stashId, sessionUser) {
|
|||
});
|
||||
}
|
||||
|
||||
async function stashMovie(movieId, stashId, sessionUser) {
|
||||
const stash = await fetchStash(stashId, sessionUser);
|
||||
|
||||
await knex('stashes_movies')
|
||||
.insert({
|
||||
stash_id: stash.id,
|
||||
movie_id: movieId,
|
||||
});
|
||||
}
|
||||
|
||||
async function unstashActor(actorId, stashId, sessionUser) {
|
||||
await knex
|
||||
.from('stashes_actors AS deletable')
|
||||
.where('deletable.actor_id', actorId)
|
||||
.where('deletable.stash_id', stashId)
|
||||
.whereExists(knex('stashes_actors') // verify user owns this stash
|
||||
.whereExists(knex('stashes_actors') // verify user owns this stash, complimentary to row-level security
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_actors.stash_id')
|
||||
.where('stashes_actors.stash_id', knex.raw('deletable.stash_id'))
|
||||
.where('stashes.user_id', sessionUser.id))
|
||||
|
|
@ -69,17 +83,31 @@ async function unstashScene(sceneId, stashId, sessionUser) {
|
|||
.from('stashes_scenes AS deletable')
|
||||
.where('deletable.scene_id', sceneId)
|
||||
.where('deletable.stash_id', stashId)
|
||||
.whereExists(knex('stashes_scenes') // verify user owns this stash
|
||||
.whereExists(knex('stashes_scenes') // verify user owns this stash, complimentary to row-level security
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_scenes.stash_id')
|
||||
.where('stashes_scenes.stash_id', knex.raw('deletable.stash_id'))
|
||||
.where('stashes.user_id', sessionUser.id))
|
||||
.delete();
|
||||
}
|
||||
|
||||
async function unstashMovie(movieId, stashId, sessionUser) {
|
||||
await knex
|
||||
.from('stashes_movies AS deletable')
|
||||
.where('deletable.movie_id', movieId)
|
||||
.where('deletable.stash_id', stashId)
|
||||
.whereExists(knex('stashes_movies') // verify user owns this stash, complimentary to row-level security
|
||||
.leftJoin('stashes', 'stashes.id', 'stashes_movies.stash_id')
|
||||
.where('stashes_movies.stash_id', knex.raw('deletable.stash_id'))
|
||||
.where('stashes.user_id', sessionUser.id))
|
||||
.delete();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
curateStash,
|
||||
stashActor,
|
||||
stashScene,
|
||||
stashMovie,
|
||||
unstashScene,
|
||||
unstashActor,
|
||||
unstashMovie,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ function curateUser(user) {
|
|||
identityVerified: user.identity_verified,
|
||||
ability,
|
||||
createdAt: user.created_at,
|
||||
stashes: user.stashes?.map(stash => curateStash(stash)) || [],
|
||||
stashes: user.stashes?.filter(Boolean).map(stash => curateStash(stash)) || [],
|
||||
};
|
||||
|
||||
return curatedUser;
|
||||
|
|
@ -26,7 +26,7 @@ function curateUser(user) {
|
|||
|
||||
async function fetchUser(userId, raw) {
|
||||
const user = await knex('users')
|
||||
.select(knex.raw('users.*, users_roles.abilities as role_abilities, json_agg(stashes) as stashes'))
|
||||
.select(knex.raw('users.*, users_roles.abilities as role_abilities, COALESCE(json_agg(stashes) FILTER (WHERE stashes.id IS NOT NULL), \'[]\') as stashes'))
|
||||
.modify((builder) => {
|
||||
if (typeof userId === 'number') {
|
||||
builder.where('users.id', userId);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
'use strict';
|
||||
|
||||
const argv = require('../argv');
|
||||
const logger = require('../logger')(__filename);
|
||||
|
||||
function errorHandler(error, req, res, _next) {
|
||||
logger.warn(`Failed to fulfill request to ${req.path}: ${error.message}`);
|
||||
|
||||
if (argv.debug) {
|
||||
logger.error(error);
|
||||
}
|
||||
|
||||
if (error.httpCode) {
|
||||
res.status(error.httpCode).send(error.message);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,10 @@ const {
|
|||
const {
|
||||
stashActor,
|
||||
stashScene,
|
||||
stashMovie,
|
||||
unstashActor,
|
||||
unstashScene,
|
||||
unstashMovie,
|
||||
} = require('./stashes');
|
||||
|
||||
async function initServer() {
|
||||
|
|
@ -83,9 +85,11 @@ async function initServer() {
|
|||
|
||||
router.post('/api/stashes/:stashId/actors', stashActor);
|
||||
router.post('/api/stashes/:stashId/scenes', stashScene);
|
||||
router.post('/api/stashes/:stashId/movies', stashMovie);
|
||||
|
||||
router.delete('/api/stashes/:stashId/actors/:actorId', unstashActor);
|
||||
router.delete('/api/stashes/:stashId/scenes/:sceneId', unstashScene);
|
||||
router.delete('/api/stashes/:stashId/movies/:movieId', unstashMovie);
|
||||
|
||||
router.get('/api/scenes', fetchScenes);
|
||||
router.get('/api/scenes/:releaseId', fetchScene);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
'use strict';
|
||||
|
||||
const { stashActor, stashScene, unstashActor, unstashScene } = require('../stashes');
|
||||
const {
|
||||
stashActor,
|
||||
stashScene,
|
||||
stashMovie,
|
||||
unstashActor,
|
||||
unstashScene,
|
||||
unstashMovie,
|
||||
} = require('../stashes');
|
||||
|
||||
async function stashActorApi(req, res) {
|
||||
await stashActor(req.body.actorId, req.params.stashId, req.session.user);
|
||||
|
|
@ -14,6 +21,12 @@ async function stashSceneApi(req, res) {
|
|||
res.status(201).send();
|
||||
}
|
||||
|
||||
async function stashMovieApi(req, res) {
|
||||
await stashMovie(req.body.movieId, req.params.stashId, req.session.user);
|
||||
|
||||
res.status(201).send();
|
||||
}
|
||||
|
||||
async function unstashActorApi(req, res) {
|
||||
await unstashActor(req.params.actorId, req.params.stashId, req.session.user);
|
||||
|
||||
|
|
@ -26,9 +39,17 @@ async function unstashSceneApi(req, res) {
|
|||
res.status(204).send();
|
||||
}
|
||||
|
||||
async function unstashMovieApi(req, res) {
|
||||
await unstashMovie(req.params.movieId, req.params.stashId, req.session.user);
|
||||
|
||||
res.status(204).send();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
stashActor: stashActorApi,
|
||||
stashScene: stashSceneApi,
|
||||
stashMovie: stashMovieApi,
|
||||
unstashActor: unstashActorApi,
|
||||
unstashScene: unstashSceneApi,
|
||||
unstashMovie: unstashMovieApi,
|
||||
};
|
||||
|
|
|
|||