Added favorites button to actor page.
This commit is contained in:
parent
e371e9725a
commit
77b40817f2
|
@ -33,6 +33,20 @@
|
||||||
:actor="actor"
|
:actor="actor"
|
||||||
class="header-social"
|
class="header-social"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Icon
|
||||||
|
v-show="me && isStashed"
|
||||||
|
icon="heart7"
|
||||||
|
class="stash stashed noselect"
|
||||||
|
@click="unstashActor"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Icon
|
||||||
|
v-show="me && !isStashed"
|
||||||
|
icon="heart8"
|
||||||
|
class="stash unstashed noselect"
|
||||||
|
@click="stashActor"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content-inner actor-inner">
|
<div class="content-inner actor-inner">
|
||||||
|
@ -54,13 +68,6 @@
|
||||||
>
|
>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<Expand
|
|
||||||
v-if="bioExpanded"
|
|
||||||
:expanded="bioExpanded"
|
|
||||||
class="expand expand-light"
|
|
||||||
@expand="(state) => bioExpanded = state"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ul class="bio nolist">
|
<ul class="bio nolist">
|
||||||
<li
|
<li
|
||||||
v-if="actor.realName"
|
v-if="actor.realName"
|
||||||
|
@ -384,7 +391,7 @@ import Scroll from '../scroll/scroll.vue';
|
||||||
import Gender from './gender.vue';
|
import Gender from './gender.vue';
|
||||||
import Social from './social.vue';
|
import Social from './social.vue';
|
||||||
|
|
||||||
async function fetchActor() {
|
async function fetchActor(scroll = true) {
|
||||||
const { actor, releases, totalCount } = await this.$store.dispatch('fetchActorById', {
|
const { actor, releases, totalCount } = await this.$store.dispatch('fetchActorById', {
|
||||||
actorId: Number(this.$route.params.actorId),
|
actorId: Number(this.$route.params.actorId),
|
||||||
limit: this.limit,
|
limit: this.limit,
|
||||||
|
@ -396,11 +403,37 @@ async function fetchActor() {
|
||||||
this.releases = releases;
|
this.releases = releases;
|
||||||
this.totalCount = totalCount;
|
this.totalCount = totalCount;
|
||||||
|
|
||||||
if (this.$refs.filter) {
|
if (this.$refs.filter && scroll) {
|
||||||
this.$refs.filter.$el.scrollIntoView();
|
this.$refs.filter.$el.scrollIntoView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function stashActor() {
|
||||||
|
this.$store.dispatch('stashActor', {
|
||||||
|
actorId: this.actor.id,
|
||||||
|
stashId: this.$store.getters.favorites.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fetchActor(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unstashActor() {
|
||||||
|
this.$store.dispatch('unstashActor', {
|
||||||
|
actorId: this.actor.id,
|
||||||
|
stashId: this.$store.getters.favorites.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fetchActor(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function me() {
|
||||||
|
return this.$store.state.auth.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isStashed() {
|
||||||
|
return this.actor.stashes?.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
function sfw() {
|
function sfw() {
|
||||||
return this.$store.state.ui.sfw;
|
return this.$store.state.ui.sfw;
|
||||||
}
|
}
|
||||||
|
@ -447,6 +480,8 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
isStashed,
|
||||||
|
me,
|
||||||
sfw,
|
sfw,
|
||||||
showAlbum,
|
showAlbum,
|
||||||
},
|
},
|
||||||
|
@ -457,6 +492,8 @@ export default {
|
||||||
mounted,
|
mounted,
|
||||||
methods: {
|
methods: {
|
||||||
fetchActor,
|
fetchActor,
|
||||||
|
stashActor,
|
||||||
|
unstashActor,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -477,11 +514,10 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: var(--lighten-extreme);
|
color: var(--lighten-extreme);
|
||||||
background: var(--profile);
|
background: var(--profile);
|
||||||
padding: .5rem 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-name {
|
.header-name {
|
||||||
padding: 0;
|
padding: .5rem 1rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@ -491,7 +527,7 @@ export default {
|
||||||
.header-gender {
|
.header-gender {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 0 0 .5rem;
|
margin: 0 0 0 .5rem;
|
||||||
transform: translate(0, .1rem);
|
transform: translate(0, .125rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-social {
|
.header-social {
|
||||||
|
@ -731,6 +767,22 @@ export default {
|
||||||
border-bottom: solid 1px var(--shadow-hint);
|
border-bottom: solid 1px var(--shadow-hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stash.icon {
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
padding: 0 1rem;
|
||||||
|
fill: var(--lighten);
|
||||||
|
|
||||||
|
&.stashed {
|
||||||
|
fill: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
fill: var(--primary);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media(max-width: $breakpoint4) {
|
@media(max-width: $breakpoint4) {
|
||||||
.descriptions-container {
|
.descriptions-container {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -795,8 +847,16 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-name {
|
.header-name {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
|
padding: .5rem .5rem .5rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stash.icon {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
padding: 0 1rem 0 .25rem;
|
||||||
|
transform: translate(0, -.1rem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -81,8 +81,8 @@
|
||||||
@input="(range) => updateValue('age', range, false)"
|
@input="(range) => updateValue('age', range, false)"
|
||||||
@change="(range) => updateValue('age', range, true)"
|
@change="(range) => updateValue('age', range, true)"
|
||||||
>
|
>
|
||||||
<template v-slot:start><Icon icon="flower" /></template>
|
<template v-slot:start><Icon icon="leaf" /></template>
|
||||||
<template v-slot:end><Icon icon="pipe" /></template>
|
<template v-slot:end><Icon icon="tree3" /></template>
|
||||||
</RangeFilter>
|
</RangeFilter>
|
||||||
|
|
||||||
<div class="filter-section">
|
<div class="filter-section">
|
||||||
|
|
|
@ -21,8 +21,10 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
async function search() {
|
async function search() {
|
||||||
this.$router.push({ name: 'search', query: { q: this.query } });
|
if (this.query) {
|
||||||
this.$emit('search');
|
this.$router.push({ name: 'search', query: { q: this.query } });
|
||||||
|
this.$emit('search');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function searching(to) {
|
function searching(to) {
|
||||||
|
|
|
@ -8,31 +8,32 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section
|
<section
|
||||||
v-if="stashes.length > 0"
|
v-if="user.stashes?.length > 0"
|
||||||
class="section"
|
class="section"
|
||||||
>
|
>
|
||||||
<h3 class="heading">Stashes</h3>
|
<h3 class="heading">Stashes</h3>
|
||||||
|
|
||||||
<ul class="stashes nolist">
|
<ul class="stashes nolist">
|
||||||
<li
|
<li
|
||||||
v-for="stash in stashes"
|
v-for="stash in user.stashes"
|
||||||
:key="stash.id"
|
:key="stash.id"
|
||||||
|
class="stash"
|
||||||
>
|
>
|
||||||
<h4 class="stash-name">{{ stash.name }}</h4>
|
<h4 class="stash-name">{{ stash.name }}</h4>
|
||||||
|
|
||||||
<ul class="stash nolist actors">
|
<ul class="stash-section stash-scenes nolist">
|
||||||
<li
|
|
||||||
v-for="item in stash.actors"
|
|
||||||
:key="item.id"
|
|
||||||
><Actor :actor="item.actor" /></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="stash nolist scenes">
|
|
||||||
<li
|
<li
|
||||||
v-for="item in stash.scenes"
|
v-for="item in stash.scenes"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
><Scene :release="item.scene" /></li>
|
><Scene :release="item.scene" /></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<ul class="stash-section stash-actors nolist">
|
||||||
|
<li
|
||||||
|
v-for="item in stash.actors"
|
||||||
|
:key="item.id"
|
||||||
|
><Actor :actor="item.actor" /></li>
|
||||||
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
@ -44,8 +45,8 @@ import Actor from '../actors/tile.vue';
|
||||||
import Scene from '../releases/scene-tile.vue';
|
import Scene from '../releases/scene-tile.vue';
|
||||||
|
|
||||||
async function mounted() {
|
async function mounted() {
|
||||||
this.user = await this.$store.dispatch('fetchMe');
|
this.user = await this.$store.dispatch('fetchUser', this.$route.params.username);
|
||||||
this.stashes = await this.$store.dispatch('fetchUserStashes', this.user.id);
|
this.pageTitle = this.user?.username;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -58,7 +59,7 @@ export default {
|
||||||
user: this.$route.params.username === this.$store.state.auth.user?.username
|
user: this.$route.params.username === this.$store.state.auth.user?.username
|
||||||
? this.$store.state.auth.user
|
? this.$store.state.auth.user
|
||||||
: null,
|
: null,
|
||||||
stashes: [],
|
pageTitle: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted,
|
mounted,
|
||||||
|
@ -67,7 +68,7 @@ export default {
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.header {
|
.header {
|
||||||
padding: 1rem;
|
padding: .5rem 1rem;
|
||||||
background: var(--profile);
|
background: var(--profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,27 +88,38 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.stash {
|
.stash {
|
||||||
|
background: var(--background);
|
||||||
margin: 0 0 1rem 0;
|
margin: 0 0 1rem 0;
|
||||||
|
box-shadow: 0 0 3px var(--shadow-weak);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stash-name {
|
.stash-name {
|
||||||
color: var(--shadow-strong);
|
color: var(--shadow-strong);
|
||||||
margin: 0 0 1rem 0;
|
padding: 1rem .5rem 0 .5rem;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actors {
|
.stash-section {
|
||||||
|
padding: 1rem .5rem;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: solid 1px var(--shadow-hint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stash-actors,
|
||||||
|
.stash-scenes {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
|
||||||
grid-gap: .5rem;
|
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scenes {
|
|
||||||
width: 100%;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
|
|
||||||
grid-gap: .5rem;
|
grid-gap: .5rem;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stash-actors {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.stash-scenes {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
color: var(--shadow-strong);
|
color: var(--shadow-strong);
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
font-family: inherit;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
border: solid 1px var(--primary);
|
border: solid 1px var(--primary);
|
||||||
|
|
|
@ -12,7 +12,7 @@ $breakpoint4: 1500px;
|
||||||
*/
|
*/
|
||||||
--primary: #f28;
|
--primary: #f28;
|
||||||
--primary-strong: #f90071;
|
--primary-strong: #f90071;
|
||||||
--primary-faded: #ff4e9f;
|
--primary-faded: #ffcce4;
|
||||||
|
|
||||||
--text-dark: #222;
|
--text-dark: #222;
|
||||||
--text-light: #fff;
|
--text-light: #fff;
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<!-- Generated by IcoMoon.io -->
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<title>leaf2</title>
|
||||||
|
<path d="M15.802 2.102c-1.73-1.311-4.393-2.094-7.124-2.094-3.377 0-6.129 1.179-7.549 3.235-0.667 0.965-1.036 2.109-1.097 3.398-0.065 1.375 0.225 2.925 0.859 4.606-0.586 1.428-0.904 2.898-0.904 4.254 0 0.276 0.224 0.5 0.5 0.5s0.5-0.224 0.5-0.5c0-1.198 0.293-2.535 0.818-3.835 1.472 0.272 2.712 0.405 3.776 0.405 1.839 0 3.146-0.398 4.115-1.252 0.868-0.765 1.347-1.794 1.854-2.882 0.774-1.663 1.651-3.547 4.198-5.002 0.146-0.083 0.24-0.234 0.251-0.402s-0.063-0.329-0.197-0.431zM10.644 7.515c-0.481 1.034-0.897 1.927-1.608 2.554-0.776 0.684-1.873 1.002-3.454 1.002-0.945 0-2.047-0.113-3.351-0.345 0.238-0.476 0.507-0.941 0.804-1.386 0.692-1.036 1.505-1.931 2.417-2.661 0.984-0.788 2.059-1.36 3.193-1.7 0.264-0.079 0.415-0.358 0.335-0.623s-0.358-0.415-0.623-0.335c-1.257 0.377-2.445 1.009-3.53 1.878-0.991 0.794-1.874 1.765-2.623 2.886-0.252 0.378-0.485 0.767-0.698 1.163-0.36-1.185-0.52-2.279-0.474-3.261 0.052-1.099 0.361-2.067 0.921-2.876 0.636-0.92 1.583-1.633 2.816-2.119 1.134-0.447 2.487-0.684 3.911-0.684 2.172 0 4.357 0.555 5.9 1.475-2.314 1.551-3.206 3.467-3.935 5.032z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1,5 @@
|
||||||
|
<!-- Generated by IcoMoon.io -->
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<title>tree2</title>
|
||||||
|
<path d="M13.887 13.182l-2.387-3.182h1c0 0 0.001 0 0.001 0 0.276 0 0.5-0.224 0.5-0.5 0-0.121-0.043-0.231-0.114-0.318l-2.387-3.182h1c0.192 0 0.367-0.11 0.451-0.283s0.060-0.379-0.060-0.529l-4-5c-0.095-0.119-0.239-0.188-0.39-0.188s-0.296 0.069-0.39 0.188l-4 5c-0.12 0.15-0.143 0.356-0.060 0.529s0.258 0.283 0.451 0.283h1l-2.4 3.2c-0.114 0.152-0.132 0.354-0.047 0.524s0.258 0.276 0.447 0.276h1l-2.4 3.2c-0.114 0.152-0.132 0.354-0.047 0.524s0.258 0.276 0.447 0.276h4.5v1.5c0 0.276 0.224 0.5 0.5 0.5h2c0.276 0 0.5-0.224 0.5-0.5v-1.5h4.5c0 0 0 0 0.001 0 0.276 0 0.5-0.224 0.5-0.5 0-0.121-0.043-0.231-0.114-0.318zM8 15h-1v-1h1v1zM2.5 13l2.4-3.2c0.114-0.152 0.132-0.354 0.047-0.524s-0.258-0.276-0.447-0.276h-1l2.4-3.2c0.114-0.152 0.132-0.354 0.047-0.524s-0.258-0.276-0.447-0.276h-0.96l2.96-3.7 2.96 3.7h-0.96c-0.189 0-0.363 0.107-0.447 0.276s-0.066 0.372 0.047 0.524l2.4 3.2h-1c-0.189 0-0.363 0.107-0.447 0.276s-0.066 0.372 0.047 0.524l2.4 3.2h-10z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,5 @@
|
||||||
|
<!-- Generated by IcoMoon.io -->
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<title>tree3</title>
|
||||||
|
<path d="M11.852 3.354c-0.508-1.928-2.266-3.354-4.352-3.354s-3.844 1.426-4.352 3.354c-1.891 0.754-3.148 2.596-3.148 4.646 0 2.757 2.243 5 5 5 0.34 0 0.674-0.035 1-0.101v2.601c0 0.276 0.224 0.5 0.5 0.5h2c0.276 0 0.5-0.224 0.5-0.5v-2.601c0.327 0.066 0.661 0.101 1 0.101 2.757 0 5-2.243 5-5 0-2.060-1.254-3.892-3.148-4.646z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 489 B |
|
@ -0,0 +1,5 @@
|
||||||
|
<!-- Generated by IcoMoon.io -->
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||||
|
<title>tree4</title>
|
||||||
|
<path d="M11.852 3.354c-0.508-1.928-2.266-3.354-4.352-3.354s-3.844 1.426-4.352 3.354c-1.891 0.754-3.148 2.596-3.148 4.646 0 2.757 2.243 5 5 5h1v2.5c0 0.276 0.224 0.5 0.5 0.5h2c0.276 0 0.5-0.224 0.5-0.5v-2.5h1c2.757 0 5-2.243 5-5 0-2.060-1.254-3.892-3.148-4.646zM8 15h-1v-2h1v2zM10 12h-5c-2.206 0-4-1.794-4-4 0-1.444 0.781-2.76 2.001-3.465 0.003 0.369 0.050 0.735 0.141 1.090 0.058 0.226 0.261 0.375 0.484 0.375 0.041 0 0.083-0.005 0.125-0.016 0.267-0.069 0.428-0.341 0.36-0.609-0.073-0.284-0.11-0.579-0.11-0.875 0-1.93 1.57-3.5 3.5-3.5s3.5 1.57 3.5 3.5c0 0.297-0.037 0.591-0.11 0.875-0.069 0.267 0.092 0.54 0.36 0.609s0.54-0.092 0.609-0.36c0.091-0.355 0.139-0.722 0.141-1.091 1.222 0.704 2.001 2.014 2.001 3.466 0 2.206-1.794 4-4 4z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 901 B |
|
@ -24,6 +24,8 @@ function initActorActions(store, router) {
|
||||||
const { actor } = await graphql(`
|
const { actor } = await graphql(`
|
||||||
query Actor(
|
query Actor(
|
||||||
$actorId: Int!
|
$actorId: Int!
|
||||||
|
$userId: Int,
|
||||||
|
$hasAuth: Boolean!,
|
||||||
$limit:Int = 10,
|
$limit:Int = 10,
|
||||||
$offset:Int = 0,
|
$offset:Int = 0,
|
||||||
$after:Datetime = "1900-01-01",
|
$after:Datetime = "1900-01-01",
|
||||||
|
@ -236,6 +238,21 @@ function initActorActions(store, router) {
|
||||||
}
|
}
|
||||||
totalCount
|
totalCount
|
||||||
}
|
}
|
||||||
|
stashes: stashesActors(
|
||||||
|
filter: {
|
||||||
|
stash: {
|
||||||
|
userId: {
|
||||||
|
equalTo: $userId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) @include(if: $hasAuth) {
|
||||||
|
stash {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, {
|
`, {
|
||||||
|
@ -253,6 +270,8 @@ function initActorActions(store, router) {
|
||||||
includedEntities: getIncludedEntities(router),
|
includedEntities: getIncludedEntities(router),
|
||||||
includedActors: getIncludedActors(router),
|
includedActors: getIncludedActors(router),
|
||||||
mode,
|
mode,
|
||||||
|
hasAuth: !!store.state.auth.user,
|
||||||
|
userId: store.state.auth.user?.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!actor) {
|
if (!actor) {
|
||||||
|
|
|
@ -10,10 +10,16 @@ async function get(endpoint, query = {}) {
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok) {
|
const contentTypes = res.headers.get('content-type');
|
||||||
|
|
||||||
|
if (res.ok && contentTypes?.includes('application/json')) {
|
||||||
return res.json();
|
return res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const errorMsg = await res.text();
|
const errorMsg = await res.text();
|
||||||
|
|
||||||
throw new Error(errorMsg);
|
throw new Error(errorMsg);
|
||||||
|
@ -30,10 +36,16 @@ async function post(endpoint, data) {
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok) {
|
const contentTypes = res.headers.get('content-type');
|
||||||
|
|
||||||
|
if (res.ok && contentTypes?.includes('application/json')) {
|
||||||
return res.json();
|
return res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const errorMsg = await res.text();
|
const errorMsg = await res.text();
|
||||||
|
|
||||||
throw new Error(errorMsg);
|
throw new Error(errorMsg);
|
||||||
|
|
|
@ -2,11 +2,16 @@ import { get, post, del } from '../api';
|
||||||
|
|
||||||
function initAuthActions(_store, _router) {
|
function initAuthActions(_store, _router) {
|
||||||
async function fetchMe({ commit }) {
|
async function fetchMe({ commit }) {
|
||||||
const user = await get('/session');
|
try {
|
||||||
|
const user = await get('/session');
|
||||||
|
|
||||||
commit('setUser', user);
|
commit('setUser', user);
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
} catch (error) {
|
||||||
|
// continue as guest
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function login({ commit }, credentials) {
|
async function login({ commit }, credentials) {
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import state from './state';
|
import state from './state';
|
||||||
import mutations from './mutations';
|
import mutations from './mutations';
|
||||||
|
import getters from './getters';
|
||||||
import actions from './actions';
|
import actions from './actions';
|
||||||
|
|
||||||
function initAuthStore(store, router) {
|
function initAuthStore(store, router) {
|
||||||
return {
|
return {
|
||||||
state,
|
state,
|
||||||
mutations,
|
mutations,
|
||||||
|
getters,
|
||||||
actions: actions(store, router),
|
actions: actions(store, router),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
function favoritesStash(state) {
|
||||||
|
return state.user.stashes.find(stash => stash.slug === 'favorites');
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
favoritesStash,
|
||||||
|
favorites: favoritesStash,
|
||||||
|
};
|
|
@ -56,6 +56,8 @@ function curateActor(actor, release) {
|
||||||
curatedActor.aliasFor = curateActor(curatedActor.aliasFor);
|
curatedActor.aliasFor = curateActor(curatedActor.aliasFor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
curatedActor.stashes = actor.stashes?.map(stash => stash.stash || stash) || [];
|
||||||
|
|
||||||
return curatedActor;
|
return curatedActor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,9 +128,7 @@ function curateTag(tag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function curateStash(stash) {
|
function curateStash(stash) {
|
||||||
const curatedStash = {
|
const curatedStash = stash;
|
||||||
...stash,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (stash.scenes) {
|
if (stash.scenes) {
|
||||||
curatedStash.scenes = stash.scenes.map(item => ({
|
curatedStash.scenes = stash.scenes.map(item => ({
|
||||||
|
@ -147,10 +147,21 @@ function curateStash(stash) {
|
||||||
return curatedStash;
|
return curatedStash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function curateUser(user) {
|
||||||
|
const curatedUser = user;
|
||||||
|
|
||||||
|
if (user.stashes) {
|
||||||
|
curatedUser.stashes = user.stashes.map(stash => curateStash(stash));
|
||||||
|
}
|
||||||
|
|
||||||
|
return curatedUser;
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
curateActor,
|
curateActor,
|
||||||
curateEntity,
|
curateEntity,
|
||||||
curateRelease,
|
curateRelease,
|
||||||
curateTag,
|
curateTag,
|
||||||
curateStash,
|
curateStash,
|
||||||
|
curateUser,
|
||||||
};
|
};
|
||||||
|
|
|
@ -64,8 +64,8 @@ async function init() {
|
||||||
return `${path}/${filename}`;
|
return `${path}/${filename}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
initUiObservers(store, router);
|
await initAuthObservers(store, router);
|
||||||
initAuthObservers(store, router);
|
await initUiObservers(store, router);
|
||||||
|
|
||||||
if (window.env.sfw) {
|
if (window.env.sfw) {
|
||||||
store.dispatch('setSfw', true);
|
store.dispatch('setSfw', true);
|
||||||
|
|
|
@ -1,101 +1,17 @@
|
||||||
import { graphql } from '../api';
|
import { post, del } from '../api';
|
||||||
import { curateStash } from '../curate';
|
|
||||||
|
|
||||||
function initStashesActions(_store, _router) {
|
function initStashesActions(_store, _router) {
|
||||||
async function fetchUserStashes(context, userId) {
|
async function stashActor(context, { actorId, stashId }) {
|
||||||
const { stashes } = await graphql(`
|
await post(`/stashes/${stashId}/actors`, { actorId });
|
||||||
query Stashes(
|
}
|
||||||
$userId: Int!
|
|
||||||
) {
|
|
||||||
stashes(
|
|
||||||
filter: {
|
|
||||||
userId: {
|
|
||||||
equalTo: $userId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
actors: stashesActors {
|
|
||||||
comment
|
|
||||||
actor {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
slug
|
|
||||||
gender
|
|
||||||
age
|
|
||||||
ageFromBirth
|
|
||||||
dateOfBirth
|
|
||||||
birthCity
|
|
||||||
birthState
|
|
||||||
birthCountry: countryByBirthCountryAlpha2 {
|
|
||||||
alpha2
|
|
||||||
name
|
|
||||||
alias
|
|
||||||
}
|
|
||||||
avatar: avatarMedia {
|
|
||||||
id
|
|
||||||
path
|
|
||||||
thumbnail
|
|
||||||
lazy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scenes: stashesScenes {
|
|
||||||
comment
|
|
||||||
scene {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
slug
|
|
||||||
url
|
|
||||||
date
|
|
||||||
actors: releasesActors {
|
|
||||||
actor {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
slug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tags: releasesTags {
|
|
||||||
tag {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
slug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
entity {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
slug
|
|
||||||
independent
|
|
||||||
parent {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
slug
|
|
||||||
independent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
poster: releasesPosterByReleaseId {
|
|
||||||
media {
|
|
||||||
path
|
|
||||||
thumbnail
|
|
||||||
lazy
|
|
||||||
isS3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`, {
|
|
||||||
userId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return stashes.map(stash => curateStash(stash));
|
async function unstashActor(context, { actorId, stashId }) {
|
||||||
|
await del(`/stashes/${stashId}/actors/${actorId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fetchUserStashes,
|
stashActor,
|
||||||
|
unstashActor,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,95 @@
|
||||||
import { get } from '../api';
|
import { graphql } from '../api';
|
||||||
|
|
||||||
function initUsersActions(_store, _router) {
|
function initUsersActions(_store, _router) {
|
||||||
async function fetchUser(context, username) {
|
async function fetchUser(context, username) {
|
||||||
const user = await get(`/users/${username}`);
|
const { user } = await graphql(`
|
||||||
|
query User(
|
||||||
|
$username: String!
|
||||||
|
) {
|
||||||
|
user: userByUsername(username: $username) {
|
||||||
|
id
|
||||||
|
role
|
||||||
|
username
|
||||||
|
stashes {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
public
|
||||||
|
actors: stashesActors {
|
||||||
|
comment
|
||||||
|
actor {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
gender
|
||||||
|
age
|
||||||
|
ageFromBirth
|
||||||
|
dateOfBirth
|
||||||
|
birthCity
|
||||||
|
birthState
|
||||||
|
birthCountry: countryByBirthCountryAlpha2 {
|
||||||
|
alpha2
|
||||||
|
name
|
||||||
|
alias
|
||||||
|
}
|
||||||
|
avatar: avatarMedia {
|
||||||
|
id
|
||||||
|
path
|
||||||
|
thumbnail
|
||||||
|
lazy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scenes: stashesScenes {
|
||||||
|
comment
|
||||||
|
scene {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
slug
|
||||||
|
url
|
||||||
|
date
|
||||||
|
actors: releasesActors {
|
||||||
|
actor {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tags: releasesTags {
|
||||||
|
tag {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entity {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
independent
|
||||||
|
parent {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
independent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poster: releasesPosterByReleaseId {
|
||||||
|
media {
|
||||||
|
path
|
||||||
|
thumbnail
|
||||||
|
lazy
|
||||||
|
isS3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, {
|
||||||
|
username,
|
||||||
|
});
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1081,6 +1081,8 @@ exports.up = knex => Promise.resolve()
|
||||||
.references('id')
|
.references('id')
|
||||||
.inTable('releases');
|
.inTable('releases');
|
||||||
|
|
||||||
|
table.unique(['stash_id', 'scene_id']);
|
||||||
|
|
||||||
table.string('comment');
|
table.string('comment');
|
||||||
}))
|
}))
|
||||||
.then(() => knex.schema.createTable('stashes_actors', (table) => {
|
.then(() => knex.schema.createTable('stashes_actors', (table) => {
|
||||||
|
@ -1094,6 +1096,8 @@ exports.up = knex => Promise.resolve()
|
||||||
.references('id')
|
.references('id')
|
||||||
.inTable('actors');
|
.inTable('actors');
|
||||||
|
|
||||||
|
table.unique(['stash_id', 'actor_id']);
|
||||||
|
|
||||||
table.string('comment');
|
table.string('comment');
|
||||||
}))
|
}))
|
||||||
// SEARCH
|
// SEARCH
|
||||||
|
@ -1295,21 +1299,24 @@ exports.up = knex => Promise.resolve()
|
||||||
GRANT ALL ON ALL TABLES IN SCHEMA public TO :visitor;
|
GRANT ALL ON ALL TABLES IN SCHEMA public TO :visitor;
|
||||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO :visitor;
|
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO :visitor;
|
||||||
|
|
||||||
|
REVOKE ALL ON users FROM :visitor;
|
||||||
|
GRANT SELECT (id, username, role, identity_verified, created_at) ON users TO :visitor;
|
||||||
|
|
||||||
ALTER TABLE stashes ENABLE ROW LEVEL SECURITY;
|
ALTER TABLE stashes ENABLE ROW LEVEL SECURITY;
|
||||||
ALTER TABLE stashes_scenes ENABLE ROW LEVEL SECURITY;
|
ALTER TABLE stashes_scenes ENABLE ROW LEVEL SECURITY;
|
||||||
ALTER TABLE stashes_actors ENABLE ROW LEVEL SECURITY;
|
ALTER TABLE stashes_actors ENABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
CREATE POLICY stashes_policy_select ON stashes FOR SELECT USING (stashes.user_id = current_user_id());
|
CREATE POLICY stashes_policy_select ON stashes FOR SELECT USING (stashes.public OR stashes.user_id = current_user_id());
|
||||||
CREATE POLICY stashes_policy_update ON stashes FOR UPDATE USING (stashes.user_id = current_user_id());
|
CREATE POLICY stashes_policy_update ON stashes FOR UPDATE USING (stashes.public OR stashes.user_id = current_user_id());
|
||||||
CREATE POLICY stashes_policy_delete ON stashes FOR DELETE USING (stashes.user_id = current_user_id());
|
CREATE POLICY stashes_policy_delete ON stashes FOR DELETE USING (stashes.public OR stashes.user_id = current_user_id());
|
||||||
CREATE POLICY stashes_policy_insert ON stashes FOR INSERT WITH CHECK(true);
|
CREATE POLICY stashes_policy_insert ON stashes FOR INSERT WITH CHECK (true);
|
||||||
|
|
||||||
CREATE POLICY stashes_policy ON stashes_scenes
|
CREATE POLICY stashes_policy ON stashes_scenes
|
||||||
USING (EXISTS (
|
USING (EXISTS (
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM stashes
|
FROM stashes
|
||||||
WHERE stashes.id = stashes_scenes.stash_id
|
WHERE stashes.id = stashes_scenes.stash_id
|
||||||
AND stashes.user_id = current_user_id()
|
AND (stashes.user_id = current_user_id() OR stashes.public)
|
||||||
));
|
));
|
||||||
|
|
||||||
CREATE POLICY stashes_policy ON stashes_actors
|
CREATE POLICY stashes_policy ON stashes_actors
|
||||||
|
@ -1317,7 +1324,7 @@ exports.up = knex => Promise.resolve()
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM stashes
|
FROM stashes
|
||||||
WHERE stashes.id = stashes_actors.stash_id
|
WHERE stashes.id = stashes_actors.stash_id
|
||||||
AND stashes.user_id = current_user_id()
|
AND (stashes.user_id = current_user_id() OR stashes.public)
|
||||||
));
|
));
|
||||||
`, {
|
`, {
|
||||||
visitor: knex.raw(config.database.query.user),
|
visitor: knex.raw(config.database.query.user),
|
||||||
|
@ -1328,8 +1335,10 @@ exports.up = knex => Promise.resolve()
|
||||||
.then(() => { // eslint-disable-line arrow-body-style
|
.then(() => { // eslint-disable-line arrow-body-style
|
||||||
// allow vim fold
|
// allow vim fold
|
||||||
return knex.raw(`
|
return knex.raw(`
|
||||||
COMMENT ON TABLE users IS E'@omit';
|
COMMENT ON COLUMN users.password IS E'@omit';
|
||||||
COMMENT ON TABLE users_roles IS E'@omit';
|
COMMENT ON COLUMN users.email IS E'@omit';
|
||||||
|
COMMENT ON COLUMN users.email_verified IS E'@omit';
|
||||||
|
COMMENT ON COLUMN users.abilities IS E'@omit';
|
||||||
|
|
||||||
COMMENT ON COLUMN actors.height IS E'@omit read,update,create,delete,all,many';
|
COMMENT ON COLUMN actors.height IS E'@omit read,update,create,delete,all,many';
|
||||||
COMMENT ON COLUMN actors.weight IS E'@omit read,update,create,delete,all,many';
|
COMMENT ON COLUMN actors.weight IS E'@omit read,update,create,delete,all,many';
|
||||||
|
|
13
src/auth.js
13
src/auth.js
|
@ -4,7 +4,7 @@ const util = require('util');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
const knex = require('./knex');
|
const knex = require('./knex');
|
||||||
const { curateUser } = require('./users');
|
const { curateUser, fetchUser } = require('./users');
|
||||||
const { HttpError } = require('./errors');
|
const { HttpError } = require('./errors');
|
||||||
|
|
||||||
const scrypt = util.promisify(crypto.scrypt);
|
const scrypt = util.promisify(crypto.scrypt);
|
||||||
|
@ -21,12 +21,7 @@ async function verifyPassword(password, storedPassword) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function login(credentials) {
|
async function login(credentials) {
|
||||||
const user = await knex('users')
|
const user = await fetchUser(credentials.username, true);
|
||||||
.select('users.*', 'users_roles.abilities as role_abilities')
|
|
||||||
.where('username', credentials.username)
|
|
||||||
.orWhere('email', credentials.username)
|
|
||||||
.leftJoin('users_roles', 'users_roles.role', 'users.role')
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new HttpError('Username or password incorrect', 401);
|
throw new HttpError('Username or password incorrect', 401);
|
||||||
|
@ -69,7 +64,7 @@ async function signup(credentials) {
|
||||||
email: credentials.email,
|
email: credentials.email,
|
||||||
password: storedPassword,
|
password: storedPassword,
|
||||||
})
|
})
|
||||||
.returning('*');
|
.returning('id');
|
||||||
|
|
||||||
await knex('stashes').insert({
|
await knex('stashes').insert({
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
|
@ -78,7 +73,7 @@ async function signup(credentials) {
|
||||||
public: false,
|
public: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return curateUser(user);
|
return fetchUser(user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const knex = require('./knex');
|
||||||
|
const { HttpError } = require('./errors');
|
||||||
|
|
||||||
|
function curateStash(stash) {
|
||||||
|
const curatedStash = {
|
||||||
|
id: stash.id,
|
||||||
|
name: stash.name,
|
||||||
|
slug: stash.slug,
|
||||||
|
};
|
||||||
|
|
||||||
|
return curatedStash;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchStash(stashId, sessionUser) {
|
||||||
|
if (!sessionUser) {
|
||||||
|
throw new HttpError('You are not authenthicated', 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const stash = await knex('stashes')
|
||||||
|
.where({
|
||||||
|
id: stashId,
|
||||||
|
user_id: sessionUser.id,
|
||||||
|
})
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (!stash) {
|
||||||
|
throw new HttpError('You are not authorized to modify this stash', 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stash;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function stashActor(actorId, stashId, sessionUser) {
|
||||||
|
const stash = await fetchStash(stashId, sessionUser);
|
||||||
|
|
||||||
|
await knex('stashes_actors')
|
||||||
|
.insert({
|
||||||
|
stash_id: stash.id,
|
||||||
|
actor_id: actorId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function stashScene(sceneId, stashId, sessionUser) {
|
||||||
|
const stash = await fetchStash(stashId, sessionUser);
|
||||||
|
|
||||||
|
await knex('stashes_scenes')
|
||||||
|
.insert({
|
||||||
|
stash_id: stash.id,
|
||||||
|
actor_id: sceneId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unstashActor(actorId, stashId, sessionUser) {
|
||||||
|
await knex
|
||||||
|
.from('stashes_actors')
|
||||||
|
.whereIn('stashes_actors.id', knex('stashes_actors')
|
||||||
|
.select('stashes_actors.id')
|
||||||
|
.leftJoin('stashes', 'stashes.id', 'stashes_actors.stash_id')
|
||||||
|
.where('stashes.user_id', sessionUser.id) // verify user owns this stash
|
||||||
|
.where('stashes_actors.actor_id', actorId)
|
||||||
|
.where('stashes_actors.stash_id', stashId))
|
||||||
|
.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
curateStash,
|
||||||
|
stashActor,
|
||||||
|
stashScene,
|
||||||
|
// unstashScene,
|
||||||
|
unstashActor,
|
||||||
|
};
|
26
src/users.js
26
src/users.js
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const knex = require('./knex');
|
const knex = require('./knex');
|
||||||
|
const { curateStash } = require('./stashes');
|
||||||
|
|
||||||
function curateUser(user) {
|
function curateUser(user) {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
@ -17,20 +18,35 @@ function curateUser(user) {
|
||||||
identityVerified: user.identity_verified,
|
identityVerified: user.identity_verified,
|
||||||
ability,
|
ability,
|
||||||
createdAt: user.created_at,
|
createdAt: user.created_at,
|
||||||
|
stashes: user.stashes?.map(stash => curateStash(stash)) || [],
|
||||||
};
|
};
|
||||||
|
|
||||||
return curatedUser;
|
return curatedUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchUser(userId) {
|
async function fetchUser(userId, raw) {
|
||||||
const user = await knex('users')
|
const user = await knex('users')
|
||||||
.select('users.*', 'users_roles.abilities as role_abilities')
|
.select(knex.raw('users.*, users_roles.abilities as role_abilities, json_agg(stashes) as stashes'))
|
||||||
.where('id', userId)
|
.modify((builder) => {
|
||||||
.orWhere('username', userId)
|
if (typeof userId === 'number') {
|
||||||
.orWhere('email', userId)
|
builder.where('users.id', userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof userId === 'string') {
|
||||||
|
builder
|
||||||
|
.where('users.username', userId)
|
||||||
|
.orWhere('users.email', userId);
|
||||||
|
}
|
||||||
|
})
|
||||||
.leftJoin('users_roles', 'users_roles.role', 'users.role')
|
.leftJoin('users_roles', 'users_roles.role', 'users.role')
|
||||||
|
.leftJoin('stashes', 'stashes.user_id', 'users.id')
|
||||||
|
.groupBy('users.id', 'users_roles.role')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
|
if (raw) {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
return curateUser(user);
|
return curateUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ async function fetchMeApi(req, res) {
|
||||||
async function signupApi(req, res) {
|
async function signupApi(req, res) {
|
||||||
const user = await signup(req.body);
|
const user = await signup(req.body);
|
||||||
|
|
||||||
|
req.session.user = user;
|
||||||
res.send(user);
|
res.send(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ module.exports = postgraphile(
|
||||||
'public',
|
'public',
|
||||||
{
|
{
|
||||||
// watchPg: true,
|
// watchPg: true,
|
||||||
|
disableDefaultMutations: true,
|
||||||
dynamicJson: true,
|
dynamicJson: true,
|
||||||
graphiql: true,
|
graphiql: true,
|
||||||
enhanceGraphiql: true,
|
enhanceGraphiql: true,
|
||||||
|
|
|
@ -43,6 +43,13 @@ const {
|
||||||
fetchTags,
|
fetchTags,
|
||||||
} = require('./tags');
|
} = require('./tags');
|
||||||
|
|
||||||
|
const {
|
||||||
|
stashActor,
|
||||||
|
stashScene,
|
||||||
|
unstashActor,
|
||||||
|
unstashScene,
|
||||||
|
} = require('./stashes');
|
||||||
|
|
||||||
async function initServer() {
|
async function initServer() {
|
||||||
const app = express();
|
const app = express();
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
@ -74,6 +81,12 @@ async function initServer() {
|
||||||
|
|
||||||
router.post('/api/users', signup);
|
router.post('/api/users', signup);
|
||||||
|
|
||||||
|
router.post('/api/stashes/:stashId/actors', stashActor);
|
||||||
|
router.post('/api/stashes/:stashId/scenes', stashScene);
|
||||||
|
|
||||||
|
router.delete('/api/stashes/:stashId/actors/:actorId', unstashActor);
|
||||||
|
router.delete('/api/stashes/:stashId/scenes/:sceneId', unstashScene);
|
||||||
|
|
||||||
router.get('/api/scenes', fetchScenes);
|
router.get('/api/scenes', fetchScenes);
|
||||||
router.get('/api/scenes/:releaseId', fetchScene);
|
router.get('/api/scenes/:releaseId', fetchScene);
|
||||||
router.get('/api/scenes/:releaseId/poster', fetchScenePoster);
|
router.get('/api/scenes/:releaseId/poster', fetchScenePoster);
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { stashActor, stashScene, unstashActor, unstashScene } = require('../stashes');
|
||||||
|
|
||||||
|
async function stashActorApi(req, res) {
|
||||||
|
await stashActor(req.body.actorId, req.params.stashId, req.session.user);
|
||||||
|
|
||||||
|
res.status(201).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function stashSceneApi(req, res) {
|
||||||
|
await stashScene(req.body.sceneId, 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);
|
||||||
|
|
||||||
|
res.status(204).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unstashSceneApi(req, res) {
|
||||||
|
await unstashScene(req.params.sceneId, req.params.stashId, req.session.user);
|
||||||
|
|
||||||
|
res.status(204).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
stashActor: stashActorApi,
|
||||||
|
stashScene: stashSceneApi,
|
||||||
|
unstashActor: unstashActorApi,
|
||||||
|
unstashScene: unstashSceneApi,
|
||||||
|
};
|
Loading…
Reference in New Issue