Exposing stashes on scenes GraphQL object.
This commit is contained in:
parent
acef14b02c
commit
f5d8c30ff3
|
@ -21,78 +21,80 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="newKey"
|
||||
class="newkey"
|
||||
>
|
||||
<p class="key-info">Successfully generated key with identifier <strong class="newkey-identifier ellipsis">{{ newKey.identifier }}</strong>:</p>
|
||||
|
||||
<input
|
||||
:value="newKey.key"
|
||||
class="input ellipsis"
|
||||
@click="copyKey"
|
||||
<div class="manager">
|
||||
<div
|
||||
v-if="newKey"
|
||||
class="newkey"
|
||||
>
|
||||
<p class="key-info">Successfully generated key with identifier <strong class="newkey-identifier ellipsis">{{ newKey.identifier }}</strong>:</p>
|
||||
|
||||
<p class="key-info">Please store this key securely, you will <strong>not</strong> be able to retrieve it later. If you lose it, you must generate a new key.</p>
|
||||
</div>
|
||||
<input
|
||||
:value="newKey.key"
|
||||
class="input ellipsis"
|
||||
@click="copyKey"
|
||||
>
|
||||
|
||||
<ul
|
||||
v-if="keys.length > 0"
|
||||
class="keys nolist"
|
||||
>
|
||||
<li
|
||||
v-for="key in keys"
|
||||
:key="`key-${key.id}`"
|
||||
class="key"
|
||||
<p class="key-info">Please store this key securely, you will <strong>not</strong> be able to retrieve it later. If you lose it, you must generate a new key.</p>
|
||||
</div>
|
||||
|
||||
<ul
|
||||
v-if="keys.length > 0"
|
||||
class="keys nolist"
|
||||
>
|
||||
<div class="key-row key-header">
|
||||
<strong class="key-value key-identifier ellipsis">{{ key.identifier }}</strong>
|
||||
<li
|
||||
v-for="key in keys"
|
||||
:key="`key-${key.id}`"
|
||||
class="key"
|
||||
>
|
||||
<div class="key-row key-header">
|
||||
<strong class="key-value key-identifier ellipsis">{{ key.identifier }}</strong>
|
||||
|
||||
<span class="key-actions">
|
||||
<Icon
|
||||
icon="bin"
|
||||
class="key-remove"
|
||||
@click="removeKey(key)"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<span class="key-actions">
|
||||
<Icon
|
||||
icon="bin"
|
||||
class="key-remove"
|
||||
@click="removeKey(key)"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="key-row key-details">
|
||||
<span class="key-value key-created">
|
||||
<Icon icon="plus-circle" />
|
||||
<div class="key-row key-details">
|
||||
<span class="key-value key-created">
|
||||
<Icon icon="plus-circle" />
|
||||
|
||||
<time
|
||||
v-tooltip="`Created ${format(key.createdAt, 'yyyy-MM-dd hh:mm:ss')}`"
|
||||
:datetime="key.createdAt.toISOString()"
|
||||
>{{ formatDistanceStrict(key.createdAt, now) }} ago</time>
|
||||
</span>
|
||||
|
||||
<span class="key-value key-used">
|
||||
<Icon icon="history" />
|
||||
|
||||
<template v-if="key.lastUsedAt">
|
||||
<time
|
||||
v-tooltip="`Last used ${format(key.lastUsedAt, 'yyyy-MM-dd hh:mm:ss')} from IP ${key.lastUsedIp}`"
|
||||
:datetime="key.lastUsedAt.toISOString()"
|
||||
>{{ formatDistanceStrict(key.lastUsedAt, now) }} ago</time>
|
||||
</template>
|
||||
v-tooltip="`Created ${format(key.createdAt, 'yyyy-MM-dd hh:mm:ss')}`"
|
||||
:datetime="key.createdAt.toISOString()"
|
||||
>{{ formatDistanceStrict(key.createdAt, now) }} ago</time>
|
||||
</span>
|
||||
|
||||
<template v-else>Never</template>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="key-value key-used">
|
||||
<Icon icon="history" />
|
||||
|
||||
<div
|
||||
v-if="keys.length > 0"
|
||||
class="info"
|
||||
>
|
||||
<h3 class="info-heading">HTTP headers</h3>
|
||||
<template v-if="key.lastUsedAt">
|
||||
<time
|
||||
v-tooltip="`Last used ${format(key.lastUsedAt, 'yyyy-MM-dd hh:mm:ss')} from IP ${key.lastUsedIp}`"
|
||||
:datetime="key.lastUsedAt.toISOString()"
|
||||
>{{ formatDistanceStrict(key.lastUsedAt, now) }} ago</time>
|
||||
</template>
|
||||
|
||||
<code class="headers">
|
||||
API-User: {{ user.id }}<br>
|
||||
API-Key: YourSecurelyStoredApiKey12345678
|
||||
</code>
|
||||
<template v-else>Never</template>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div
|
||||
v-if="keys.length > 0"
|
||||
class="info"
|
||||
>
|
||||
<h3 class="info-heading">HTTP headers</h3>
|
||||
|
||||
<code class="headers">
|
||||
API-User: {{ user.id }}<br>
|
||||
API-Key: YourSecurelyStoredApiKey12345678
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
@ -151,18 +153,6 @@ function copyKey(event) {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.manager {
|
||||
width: 1200px;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.keys-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
@ -297,7 +287,17 @@ function copyKey(event) {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
@media(--compact) {
|
||||
.manager {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media(--small-20) {
|
||||
.manager {
|
||||
padding: 0 .5rem;
|
||||
}
|
||||
|
||||
.keys {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import Router from 'express-promise-router';
|
||||
|
||||
import {
|
||||
fetchAlerts,
|
||||
createAlert,
|
||||
|
@ -7,18 +9,124 @@ import {
|
|||
updateNotification,
|
||||
} from '../alerts.js';
|
||||
|
||||
export const alertsSchema = `
|
||||
extend type Query {
|
||||
alerts: [Alert]
|
||||
|
||||
alert(
|
||||
id: Int!
|
||||
): Alert
|
||||
}
|
||||
|
||||
extend type Mutation {
|
||||
createAlert(
|
||||
all: Boolean = true
|
||||
allActors: Boolean = true
|
||||
allTags: Boolean = true
|
||||
allMatches: Boolean = true
|
||||
actors: [Int!]
|
||||
tags: [Int!]
|
||||
entities: [Int!]
|
||||
matches: [AlertMatchInput!]
|
||||
notify: Boolean = true
|
||||
email: Boolean = false
|
||||
stashes: [Int!]
|
||||
): Alert
|
||||
}
|
||||
|
||||
type AlertAnd {
|
||||
fields: Boolean
|
||||
actors: Boolean
|
||||
tags: Boolean
|
||||
entities: Boolean
|
||||
matches: Boolean
|
||||
}
|
||||
|
||||
type AlertActor {
|
||||
id: Int
|
||||
name: String
|
||||
slug: String
|
||||
}
|
||||
|
||||
type AlertTag {
|
||||
id: Int
|
||||
name: String
|
||||
slug: String
|
||||
}
|
||||
|
||||
enum EntityType {
|
||||
network
|
||||
channel
|
||||
studio
|
||||
info
|
||||
}
|
||||
|
||||
type AlertEntity {
|
||||
id: Int
|
||||
name: String
|
||||
slug: String
|
||||
type: EntityType
|
||||
}
|
||||
|
||||
type AlertMatch {
|
||||
id: Int
|
||||
property: String
|
||||
expression: String
|
||||
}
|
||||
|
||||
input AlertMatchInput {
|
||||
property: String!
|
||||
expression: String!
|
||||
}
|
||||
|
||||
type AlertStash {
|
||||
id: Int
|
||||
name: String
|
||||
slug: String
|
||||
isPrimary: Boolean
|
||||
}
|
||||
|
||||
type Alert {
|
||||
id: Int
|
||||
notify: Boolean
|
||||
email: Boolean
|
||||
isFromPreset: Boolean
|
||||
isPrimary: Boolean
|
||||
createdAt: Date
|
||||
and: AlertAnd
|
||||
actors: [AlertActor]
|
||||
tags: [AlertTag]
|
||||
entities: [AlertEntity]
|
||||
matches: [AlertMatch]
|
||||
stashes: [AlertStash]
|
||||
}
|
||||
`;
|
||||
|
||||
export async function fetchAlertsApi(req, res) {
|
||||
const alerts = await fetchAlerts(req.user);
|
||||
|
||||
res.send(alerts);
|
||||
}
|
||||
|
||||
export async function fetchAlertsGraphql(query, req) {
|
||||
const alerts = await fetchAlerts(req.user);
|
||||
|
||||
return alerts;
|
||||
}
|
||||
|
||||
export async function createAlertApi(req, res) {
|
||||
const alert = await createAlert(req.body, req.user);
|
||||
|
||||
res.send(alert);
|
||||
}
|
||||
|
||||
export async function createAlertGraphql(query, req) {
|
||||
console.log('CREATE ALERT', query);
|
||||
const alert = await createAlert(query, req.user);
|
||||
|
||||
return alert;
|
||||
}
|
||||
|
||||
export async function removeAlertApi(req, res) {
|
||||
await Promise.all(req.params.alertId.split(',').map(async (alertId) => removeAlert(alertId, req.user)));
|
||||
|
||||
|
@ -44,3 +152,13 @@ export async function updateNotificationApi(req, res) {
|
|||
|
||||
res.status(204).send();
|
||||
}
|
||||
|
||||
export const router = Router();
|
||||
|
||||
router.get('/api/alerts', fetchAlertsApi);
|
||||
router.post('/api/alerts', createAlertApi);
|
||||
router.delete('/api/alerts/:alertId', removeAlertApi);
|
||||
|
||||
router.get('/api/users/:userId/notifications', fetchNotificationsApi);
|
||||
router.patch('/api/users/:userId/notifications', updateNotificationsApi);
|
||||
router.patch('/api/users/:userId/notifications/:notificationId', updateNotificationApi);
|
||||
|
|
|
@ -46,6 +46,12 @@ import {
|
|||
unstashMovieGraphql,
|
||||
} from './stashes.js';
|
||||
|
||||
import {
|
||||
alertsSchema,
|
||||
fetchAlertsGraphql,
|
||||
createAlertGraphql,
|
||||
} from './alerts.js';
|
||||
|
||||
import { verifyKey } from '../auth.js';
|
||||
|
||||
const schema = buildSchema(`
|
||||
|
@ -64,6 +70,7 @@ const schema = buildSchema(`
|
|||
${actorsSchema}
|
||||
${entitiesSchema}
|
||||
${stashesSchema}
|
||||
${alertsSchema}
|
||||
`);
|
||||
|
||||
const DateTimeScalar = new GraphQLScalarType({
|
||||
|
@ -125,7 +132,8 @@ export async function graphqlApi(req, res) {
|
|||
entitiesById: async (query, args, info) => fetchEntitiesByIdGraphql(query, req, info),
|
||||
stashes: async (query) => fetchUserStashesGraphql(query, req),
|
||||
stash: async (query) => fetchStashGraphql(query, req),
|
||||
// mutation
|
||||
alerts: async (query) => fetchAlertsGraphql(query, req),
|
||||
// stash mutation
|
||||
createStash: async (query) => createStashGraphql(query, req),
|
||||
updateStash: async (query) => updateStashGraphql(query, req),
|
||||
removeStash: async (query) => removeStashGraphql(query, req),
|
||||
|
@ -135,10 +143,12 @@ export async function graphqlApi(req, res) {
|
|||
unstashActor: async (query) => unstashActorGraphql(query, req),
|
||||
stashMovie: async (query) => stashMovieGraphql(query, req),
|
||||
unstashMovie: async (query) => unstashMovieGraphql(query, req),
|
||||
// alert mutation
|
||||
createAlert: async (query) => createAlertGraphql(query, req),
|
||||
},
|
||||
});
|
||||
|
||||
const statusCode = data.errors?.[0]?.originalError.httpCode || 200;
|
||||
const statusCode = data.errors?.[0]?.originalError?.httpCode || 200;
|
||||
|
||||
res.status(statusCode).send(data);
|
||||
}
|
||||
|
|
|
@ -132,6 +132,7 @@ export const scenesSchema = `
|
|||
photos: [Media!]!
|
||||
covers: [Media!]!
|
||||
movies: [Release!]!
|
||||
stashes: [Stash!]
|
||||
}
|
||||
|
||||
type Tag {
|
||||
|
|
|
@ -38,15 +38,7 @@ import {
|
|||
|
||||
import { router as userRouter } from './users.js';
|
||||
import { router as stashesRouter } from './stashes.js';
|
||||
|
||||
import {
|
||||
fetchAlertsApi,
|
||||
createAlertApi,
|
||||
removeAlertApi,
|
||||
fetchNotificationsApi,
|
||||
updateNotificationApi,
|
||||
updateNotificationsApi,
|
||||
} from './alerts.js';
|
||||
import { router as alertsRouter } from './alerts.js';
|
||||
|
||||
import initLogger from '../logger.js';
|
||||
|
||||
|
@ -140,23 +132,15 @@ export default async function initServer() {
|
|||
// USERS
|
||||
router.post('/api/users', signupApi);
|
||||
|
||||
router.get('/api/users/:userId/notifications', fetchNotificationsApi);
|
||||
router.patch('/api/users/:userId/notifications', updateNotificationsApi);
|
||||
router.patch('/api/users/:userId/notifications/:notificationId', updateNotificationApi);
|
||||
|
||||
// API KEYS
|
||||
router.get('/api/me/keys', fetchUserKeysApi);
|
||||
router.post('/api/me/keys', createKeyApi);
|
||||
router.delete('/api/me/keys/:keyIdentifier', removeUserKeyApi);
|
||||
router.delete('/api/me/keys', flushUserKeysApi);
|
||||
|
||||
// ALERTS
|
||||
router.get('/api/alerts', fetchAlertsApi);
|
||||
router.post('/api/alerts', createAlertApi);
|
||||
router.delete('/api/alerts/:alertId', removeAlertApi);
|
||||
|
||||
router.use(userRouter);
|
||||
router.use(stashesRouter);
|
||||
router.use(alertsRouter);
|
||||
router.use(scenesRouter);
|
||||
router.use(actorsRouter);
|
||||
|
||||
|
|
Loading…
Reference in New Issue