style(*): cleanup unused imports

This commit is contained in:
parent 5baa00bbb4
commit c8e84c909e
Signed by: tablet
GPG Key ID: 924A5F6AF051E87C
53 changed files with 195 additions and 748 deletions

@ -3,6 +3,5 @@
"useTabs": true, "useTabs": true,
"trailingComma": "all", "trailingComma": "all",
"arrowParens": "always", "arrowParens": "always",
"vueIndentScriptAndStyle": true, "vueIndentScriptAndStyle": true
"editorconfig": true
} }

@ -1,14 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { theme } from "ant-design-vue";
const { getSession, signIn } = useAuth(); const { getSession, signIn } = useAuth();
await getSession({ force: true }); await getSession({ force: true });
const { data } = await useAuth(); const { data } = await useAuth();
const dop = data?.value as any; let darkBool = ref(data.value?.user?.profile?.nightMode || false);
let darkBool = ref(dop?.user?.profile?.nightMode || false);
// provide("user", ref(dop?.user || null)); // provide("user", ref(dop?.user || null));
provide("dark", darkBool); provide("dark", darkBool);
useHead({ useHead({
@ -17,8 +14,7 @@
return darkBool.value ? "dark" : undefined; return darkBool.value ? "dark" : undefined;
}).value, }).value,
}, },
titleTemplate: (title) => titleTemplate: (title) => (title ? `Rockfic | ${title}` : "Rockfic | Band fiction that rocks"),
title ? `Rockfic | ${title}` : "Rockfic | Band fiction that rocks",
}); });
// provide("loaded", useNuxtApp().$loaded); // provide("loaded", useNuxtApp().$loaded);
// let loaded = ref<boolean[]>([]); // let loaded = ref<boolean[]>([]);

@ -1,9 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import TinymceEditor from "@tinymce/tinymce-vue"; import TinymceEditor from "@tinymce/tinymce-vue";
import { useDark } from "@vueuse/core";
import { NamePath } from "ant-design-vue/es/form/interface";
import { Field as VeeField } from "vee-validate"; import { Field as VeeField } from "vee-validate";
import tinymce from "tinymce";
const props = defineProps<{ const props = defineProps<{
name: string; name: string;
init: any; init: any;
@ -16,17 +14,8 @@
</script> </script>
<template> <template>
<ClientOnly> <ClientOnly>
<vee-field <vee-field :name="props.name" v-slot="{ errorMessage, field, value }" :model-value="props.val">
:name="props.name" <a-form-item :validate-status="!!errorMessage ? 'error' : ''" :name="props.name" :label="props.label as any" :help="errorMessage">
v-slot="{ errorMessage, field, value }"
:model-value="props.val"
>
<a-form-item
:validate-status="!!errorMessage ? 'error' : ''"
:name="props.name"
:label="props.label as any"
:help="errorMessage"
>
<tinymce-editor <tinymce-editor
v-bind="field" v-bind="field"
width="100%" width="100%"

@ -1,7 +1,4 @@
<script lang="ts" setup> <script lang="ts" setup>
import { log } from "@server/logger";
import { MenuProps } from "ant-design-vue";
const { data, status } = useAuth(); const { data, status } = useAuth();
const itemMap = ref({ const itemMap = ref({
home: "/", home: "/",
@ -18,11 +15,7 @@
admin: "/admin", admin: "/admin",
logout: "/auth/logout", logout: "/auth/logout",
}); });
let cur = ref<string>( let cur = ref<string>(Object.keys(itemMap.value).find((a) => itemMap.value[a] === useRoute().path) || useRoute().path);
Object.keys(itemMap.value).find(
(a) => itemMap.value[a] === useRoute().path,
) || useRoute().path,
);
let selected: string[] = [cur.value]; let selected: string[] = [cur.value];
const clickFn = (minfo) => { const clickFn = (minfo) => {
@ -61,18 +54,11 @@
<a-menu-item key="reviews"> Manage Reviews </a-menu-item> <a-menu-item key="reviews"> Manage Reviews </a-menu-item>
<a-menu-item key="messages"> Private Messages </a-menu-item> <a-menu-item key="messages"> Private Messages </a-menu-item>
</a-sub-menu> </a-sub-menu>
<a-menu-item key="admin" v-if="data?.user?.profile.isAdmin || false"> <a-menu-item key="admin" v-if="data?.user?.profile.isAdmin || false"> Admin </a-menu-item>
Admin
</a-menu-item>
<a-menu-item key="logout" v-if="!!data?.user"> Logout </a-menu-item> <a-menu-item key="logout" v-if="!!data?.user"> Logout </a-menu-item>
</a-menu> </a-menu>
<div> <div>
<a-button <a-button v-if="data?.user" type="primary" tooltip="Post a New Story" @click="() => navigateTo('/new-story')">
v-if="data?.user"
type="primary"
tooltip="Post a New Story"
@click="() => navigateTo('/new-story')"
>
<!-- <template #icon> <!-- <template #icon>
</template> --> </template> -->
<icon istyle="regular" name="file-plus" /> <icon istyle="regular" name="file-plus" />
@ -80,16 +66,8 @@
</a-button> </a-button>
</div> </div>
<div class="acbut" v-if="!data"> <div class="acbut" v-if="!data">
<a-button size="large" @click="() => navigateTo('/auth/login')"> <a-button size="large" @click="() => navigateTo('/auth/login')"> Login </a-button>
Login <a-button size="large" type="primary" @click="() => navigateTo('/auth/register')"> Register </a-button>
</a-button>
<a-button
size="large"
type="primary"
@click="() => navigateTo('/auth/register')"
>
Register
</a-button>
</div> </div>
</div> </div>
</template> </template>

@ -1,12 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { import type { MenuItemType, SubMenuType } from "ant-design-vue/es/menu/src/interface";
MenuItemType,
SubMenuType,
} from "ant-design-vue/es/menu/src/interface";
import { ItemType, theme } from "ant-design-vue"; import { ItemType, theme } from "ant-design-vue";
import Icon from "../icon.vue"; import Icon from "../icon.vue";
import { ISidebarItem } from "@models/sidebarEntry"; import { ISidebarItem } from "@models/sidebarEntry";
import { AButton, NuxtLink } from "#components"; import { NuxtLink } from "#components";
const loaded = inject<Ref<boolean>>("loaded"); const loaded = inject<Ref<boolean>>("loaded");

@ -1,6 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { IStory } from "@models/stories"; import type { IStory } from "@models/stories";
import { log } from "~/lib/server/logger";
import { format } from "date-fns"; import { format } from "date-fns";
import icon from "../icon.vue"; import icon from "../icon.vue";
import { theme } from "ant-design-vue"; import { theme } from "ant-design-vue";
@ -14,18 +13,8 @@
const idxo = (prop.last || false ? prop.story.chapters.length : 1) - 1; const idxo = (prop.last || false ? prop.story.chapters.length : 1) - 1;
// console.log("idx0->", idxo) // console.log("idx0->", idxo)
// log.debug("posti->", prop.story.chapters[ prop.story.chapters.length - 1 ]); // log.debug("posti->", prop.story.chapters[ prop.story.chapters.length - 1 ]);
const shortDate = format( const shortDate = format(Date.parse(prop.story.chapters[prop.story.chapters.length - 1]?.posted!.toString()), "yyyy/MM/dd");
Date.parse( const longDate = format(Date.parse(prop.story.chapters[prop.story.chapters.length - 1]?.posted!.toString()), "iiii',' yyyy-MM-dd");
prop.story.chapters[prop.story.chapters.length - 1]?.posted!.toString(),
),
"yyyy/MM/dd",
);
const longDate = format(
Date.parse(
prop.story.chapters[prop.story.chapters.length - 1]?.posted!.toString(),
),
"iiii',' yyyy-MM-dd",
);
</script> </script>
<template> <template>
<a-card> <a-card>
@ -36,26 +25,16 @@
{{ story.title }} {{ story.title }}
</NuxtLink> </NuxtLink>
<a-tooltip placement="topLeft"> <a-tooltip placement="topLeft">
<template #title> <template #title> You'll need to log in to read this story. Register if you don't already have an account -- it's free! </template>
You'll need to log in to read this story. Register if you don't
already have an account -- it's free!
</template>
<icon v-if="!data?.user" istyle="solid" name="lock" /> <icon v-if="!data?.user" istyle="solid" name="lock" />
</a-tooltip> </a-tooltip>
</div> </div>
<div <div style="display: flex; font-size: 0.9em; align-items: baseline" class="headerthing">
style="display: flex; font-size: 0.9em; align-items: baseline"
class="headerthing"
>
<span> a </span> <span> a </span>
<div <div style="" v-for="(band, idx) in story.chapters[idxo].bands.filter((a) => !!a)">
style=""
v-for="(band, idx) in story.chapters[idxo].bands.filter((a) => !!a)"
>
<span> <span>
<NuxtLink :to="`/band/${band._id}`"> {{ band.name }} </NuxtLink <NuxtLink :to="`/band/${band._id}`"> {{ band.name }} </NuxtLink>{{ idx < story.chapters[idxo].bands.length - 1 ? ", " : "" }}
>{{ idx < story.chapters[idxo].bands.length - 1 ? ", " : "" }}
</span> </span>
</div> </div>
<span> fic by </span> <span> fic by </span>
@ -100,9 +79,7 @@
<div class="storyMeta"> <div class="storyMeta">
<div class="inner"> <div class="inner">
<span v-if="story.chapters.length > 1"> <span v-if="story.chapters.length > 1">
<NuxtLink :to="`/story/${story._id}/chapters`"> <NuxtLink :to="`/story/${story._id}/chapters`"> {{ story.chapters.length }} chapters </NuxtLink>
{{ story.chapters.length }} chapters
</NuxtLink>
</span> </span>
<span v-else> {{ story.chapters.length }} chapter </span> <span v-else> {{ story.chapters.length }} chapter </span>
<span> <span>
@ -121,15 +98,10 @@
{{ story.chapters[idxo].characters.join(", ") }} {{ story.chapters[idxo].characters.join(", ") }}
</meta-item> </meta-item>
<meta-item label="Relationship(s)"> <meta-item label="Relationship(s)">
<div <div style="display: inline-block" v-for="(rel, idx) in story.chapters[idxo].relationships">
style="display: inline-block"
v-for="(rel, idx) in story.chapters[idxo].relationships"
>
<span> <span>
{{ Array.isArray(rel) ? rel.join("/") : rel }} {{ Array.isArray(rel) ? rel.join("/") : rel }}
{{ {{ idx < story.chapters[idxo].relationships.length - 1 ? "," : "" }}
idx < story.chapters[idxo].relationships.length - 1 ? "," : ""
}}
</span> </span>
</div> </div>
<span v-if="story.chapters[idxo].relationships.length < 1"> <span v-if="story.chapters[idxo].relationships.length < 1">
@ -149,12 +121,7 @@
<div class="stats"> <div class="stats">
<span> <span>
<span class="staticon"> <span class="staticon">
<icon <icon :istyle="!dark ? 'solid' : 'regular'" icolor="#ff2883" :size="12" name="heart" />
:istyle="!dark ? 'solid' : 'regular'"
icolor="#ff2883"
:size="12"
name="heart"
/>
</span> </span>
<span> <span>
{{ story.favs }} {{ story.favs }}
@ -162,12 +129,7 @@
</span> </span>
<span> <span>
<span class="staticon"> <span class="staticon">
<icon <icon :istyle="!dark ? 'solid' : 'regular'" icolor="#1787d7" :size="12" name="book-open" />
:istyle="!dark ? 'solid' : 'regular'"
icolor="#1787d7"
:size="12"
name="book-open"
/>
</span> </span>
<span> <span>
{{ story.views }} {{ story.views }}
@ -175,12 +137,7 @@
</span> </span>
<span> <span>
<span class="staticon"> <span class="staticon">
<icon <icon :istyle="!dark ? 'solid' : 'regular'" icolor="#51e07c" :size="12" name="thumbs-up" />
:istyle="!dark ? 'solid' : 'regular'"
icolor="#51e07c"
:size="12"
name="thumbs-up"
/>
</span> </span>
<span> <span>
{{ story.recs }} {{ story.recs }}
@ -188,12 +145,7 @@
</span> </span>
<span> <span>
<span class="staticon"> <span class="staticon">
<icon <icon :istyle="!dark ? 'solid' : 'regular'" icolor="#c2d420" :size="12" name="download" />
:istyle="!dark ? 'solid' : 'regular'"
icolor="#c2d420"
:size="12"
name="download"
/>
</span> </span>
<span> <span>
{{ story.downloads }} {{ story.downloads }}

@ -1,5 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Form as veeForm, Field as veeField, useForm } from "vee-validate"; import { Form as veeForm, Field as veeField } from "vee-validate";
import { IReview } from "@models/stories/review"; import { IReview } from "@models/stories/review";
import { comment } from "@client/editorConfig"; import { comment } from "@client/editorConfig";
import { SingleChapterResult } from "@client/types/slightlyDifferentStory"; import { SingleChapterResult } from "@client/types/slightlyDifferentStory";
@ -25,13 +25,10 @@
}; };
const replySubmit = async (values) => { const replySubmit = async (values) => {
const { data } = await useApiFetch<any>( const { data } = await useApiFetch<any>(`/review/${props.review._id}/reply`, {
`/review/${props.review._id}/reply`, method: "post",
{ body: values,
method: "post", });
body: values,
},
);
review.value.replies.push(data.value.data); review.value.replies.push(data.value.data);
replyFormVisible.value = false; replyFormVisible.value = false;
}; };
@ -49,12 +46,7 @@
<a-comment> <a-comment>
<template #actions> <template #actions>
<div v-if="!!data?.user" class="review-actions"> <div v-if="!!data?.user" class="review-actions">
<a-button <a-button v-if="isCommentAuthor" @click="() => (isEditing = !isEditing)"> Edit </a-button>
v-if="isCommentAuthor"
@click="() => (isEditing = !isEditing)"
>
Edit
</a-button>
<a-popconfirm <a-popconfirm
title="Are you sure you want to permanently delete this review?" title="Are you sure you want to permanently delete this review?"
ok-text="Yes" ok-text="Yes"
@ -64,13 +56,7 @@
> >
<a-button> Delete </a-button> <a-button> Delete </a-button>
</a-popconfirm> </a-popconfirm>
<a-button <a-button v-if="isAuthor" type="primary" @click="() => (replyFormVisible = !replyFormVisible)"> Reply </a-button>
v-if="isAuthor"
type="primary"
@click="() => (replyFormVisible = !replyFormVisible)"
>
Reply
</a-button>
</div> </div>
</template> </template>
<template #author> <template #author>
@ -91,25 +77,14 @@
<div> <div>
<vee-form @submit="editSubmit" v-if="isEditing"> <vee-form @submit="editSubmit" v-if="isEditing">
<vee-field name="content" v-slot="{ value, field, errorMessage }"> <vee-field name="content" v-slot="{ value, field, errorMessage }">
<base-editor <base-editor :val="review.text" :width="150" label="" :name="field.name" :init="comment" />
:val="review.text"
:width="150"
label=""
:name="field.name"
:init="comment"
/>
</vee-field> </vee-field>
<a-button type="primary" html-type="submit"> Edit review </a-button> <a-button type="primary" html-type="submit"> Edit review </a-button>
</vee-form> </vee-form>
<div v-else v-html="review.text" /> <div v-else v-html="review.text" />
<vee-form @submit="replySubmit" v-if="replyFormVisible"> <vee-form @submit="replySubmit" v-if="replyFormVisible">
<vee-field name="content" v-slot="{ value, field, errorMessage }"> <vee-field name="content" v-slot="{ value, field, errorMessage }">
<base-editor <base-editor :width="150" label="" :name="field.name" :init="comment" />
:width="150"
label=""
:name="field.name"
:init="comment"
/>
</vee-field> </vee-field>
<a-button type="primary" html-type="submit"> Post response </a-button> <a-button type="primary" html-type="submit"> Post response </a-button>
</vee-form> </vee-form>

@ -3,9 +3,6 @@
import { RuleExpression, useField } from "vee-validate"; import { RuleExpression, useField } from "vee-validate";
import { cs } from "@client/storyFormSchema"; import { cs } from "@client/storyFormSchema";
import { IBand } from "@models/band"; import { IBand } from "@models/band";
import { log } from "@server/logger";
import iconEl from "../icon.vue";
const bandlist = inject<IBand[]>("bandlist"); const bandlist = inject<IBand[]>("bandlist");
const fname = inject<string>("curName"); const fname = inject<string>("curName");
@ -19,20 +16,13 @@
label: a.name, label: a.name,
disabled: a.locked || false, disabled: a.locked || false,
})); }));
let bandField = useField( let bandField = useField(fname + "bands", cs.fields.bands as unknown as MaybeRef<RuleExpression<number[]>>);
fname + "bands",
cs.fields.bands as unknown as MaybeRef<RuleExpression<number[]>>,
);
const { value, errorMessage, name, setValue } = bandField; const { value, errorMessage, name, setValue } = bandField;
// setValue(sb) // setValue(sb)
</script> </script>
<template> <template>
<a-form-item <a-form-item :validate-status="!!errorMessage ? 'error' : undefined" :help="errorMessage as any" label="Bands">
:validate-status="!!errorMessage ? 'error' : undefined"
:help="errorMessage"
label="Bands"
>
<a-select <a-select
:allow-clear="true" :allow-clear="true"
mode="multiple" mode="multiple"

@ -1,15 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { import { Field, ErrorMessage } from "vee-validate";
Form as VeeForm,
Field,
useForm,
useField,
ErrorMessage,
} from "vee-validate";
import { NamePath } from "ant-design-vue/es/form/interface"; import { NamePath } from "ant-design-vue/es/form/interface";
import { FormChapter } from "@client/types/form/story"; import { FormChapter } from "@client/types/form/story";
import { story, bare } from "@client/editorConfig"; import { bare } from "@client/editorConfig";
import elBands from "../atoms/bands.vue"; import elBands from "../atoms/bands.vue";
import genre from "../atoms/genre.vue"; import genre from "../atoms/genre.vue";
import elCharacters from "../atoms/characters.vue"; import elCharacters from "../atoms/characters.vue";
@ -41,16 +35,8 @@
<div> <div>
<a-row :gutter="[10, 0]"> <a-row :gutter="[10, 0]">
<a-col :span="12"> <a-col :span="12">
<Field <Field :name="name + '.chapterTitle'" v-slot="{ value, field, errorMessage }">
:name="name + '.chapterTitle'" <a-form-item :name="[field.name as string]" label="Chapter title" :help="errorMessage" :status="!!errorMessage ? 'error' : undefined">
v-slot="{ value, field, errorMessage }"
>
<a-form-item
:name="[field.name]"
label="Chapter title"
:help="errorMessage"
:status="!!errorMessage ? 'error' : undefined"
>
<a-input v-bind="field" /> <a-input v-bind="field" />
</a-form-item> </a-form-item>
</Field> </Field>
@ -61,22 +47,10 @@
</a-row> </a-row>
<a-row :gutter="[10, 0]"> <a-row :gutter="[10, 0]">
<a-col :span="12"> <a-col :span="12">
<base-editor <base-editor v-model:val="acData.summary" :name="name + '.summary'" :wrap-col="wrapc" label="Summary" :init="bare" />
v-model:val="acData.summary"
:name="name + '.summary'"
:wrap-col="wrapc"
label="Summary"
:init="bare"
/>
</a-col> </a-col>
<a-col :span="12"> <a-col :span="12">
<base-editor <base-editor v-model:val="acData.notes" :name="name + '.notes'" :wrap-col="wrapc" label="Author's notes" :init="bare" />
v-model:val="acData.notes"
:name="name + '.notes'"
:wrap-col="wrapc"
label="Author's notes"
:init="bare"
/>
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="[10, 0]"> <a-row :gutter="[10, 0]">
@ -87,39 +61,17 @@
<el-pairings /> <el-pairings />
</a-col> </a-col>
</a-row> </a-row>
<Field <Field :name="name + '.nsfw'" type="checkbox" :unchecked-value="false" :value="true" v-slot="{ value, field, errorMessage }">
:name="name + '.nsfw'" <a-checkbox v-bind="field" v-model="field.value"> Has NSFW content </a-checkbox>
type="checkbox"
:unchecked-value="false"
:value="true"
v-slot="{ value, field, errorMessage }"
>
<a-checkbox v-bind="field" v-model="field.value">
Has NSFW content
</a-checkbox>
<error-message :name="field.name" /> <error-message :name="field.name" />
</Field> </Field>
<Field <Field :name="name + '.loggedInOnly'" type="checkbox" :unchecked-value="false" :value="true" v-slot="{ value, field, errorMessage }">
:name="name + '.loggedInOnly'"
type="checkbox"
:unchecked-value="false"
:value="true"
v-slot="{ value, field, errorMessage }"
>
<a-checkbox v-bind="field"> Visible only to registered users </a-checkbox> <a-checkbox v-bind="field"> Visible only to registered users </a-checkbox>
<error-message :name="field.name" /> <error-message :name="field.name" />
</Field> </Field>
<Field <Field :name="name + '.hidden'" type="checkbox" :unchecked-value="false" :value="true" v-slot="{ value, field, errorMessage }">
:name="name + '.hidden'"
type="checkbox"
:unchecked-value="false"
:value="true"
v-slot="{ value, field, errorMessage }"
>
<a-tooltip> <a-tooltip>
<template #title> <template #title> Hides your story from everyone except you and site admins. </template>
Hides your story from everyone except you and site admins.
</template>
<a-checkbox v-bind="field"> Hidden </a-checkbox> <a-checkbox v-bind="field"> Hidden </a-checkbox>
</a-tooltip> </a-tooltip>
</Field> </Field>

@ -2,25 +2,10 @@
import draggable from "vuedraggable"; import draggable from "vuedraggable";
import { v4 } from "uuid"; import { v4 } from "uuid";
import lmove from "lodash-move"; import lmove from "lodash-move";
import { import { Field, FieldArray, useForm } from "vee-validate";
Field,
Form as veeForm,
FieldArray,
FieldEntry,
useForm,
} from "vee-validate";
import { storySchema } from "@client/storyFormSchema"; import { storySchema } from "@client/storyFormSchema";
import { import { FormStory, defaultChapter } from "@client/types/form/story";
FormChapter, import { autoEdit, autoSave, debouncedAutoEdit, debouncedAutoSave } from "@client/utils";
FormStory,
defaultChapter,
} from "@client/types/form/story";
import {
autoEdit,
autoSave,
debouncedAutoEdit,
debouncedAutoSave,
} from "@client/utils";
import findUser from "~/components/findUser.vue"; import findUser from "~/components/findUser.vue";
@ -79,35 +64,17 @@
@submit="onSubmit" @submit="onSubmit"
@invalid-submit="inval" @invalid-submit="inval"
> --> > -->
<form <form @submit="subCb" @change="() => (canDraft ? debouncedAutoSave(values) : debouncedAutoEdit(values, endpoint, endpointMethod))">
@submit="subCb"
@change="
() =>
canDraft
? debouncedAutoSave(values)
: debouncedAutoEdit(values, endpoint, endpointMethod)
"
>
<!-- <a-form v-bind:model="acData"> --> <!-- <a-form v-bind:model="acData"> -->
<Field name="title" v-slot="{ value, field, errorMessage }"> <Field name="title" v-slot="{ value, field, errorMessage }">
<a-form-item <a-form-item label="Title" :help="errorMessage" :validate-status="!!errorMessage ? 'error' : ''">
label="Title"
:help="errorMessage"
:validate-status="!!errorMessage ? 'error' : ''"
>
<a-input v-bind="field" :value="value" /> <a-input v-bind="field" :value="value" />
</a-form-item> </a-form-item>
</Field> </Field>
<a-form-item label="Co-author (optional)"> <a-form-item label="Co-author (optional)">
<find-user :initial-option="null" fieldName="coAuthor" :multi="false" /> <find-user :initial-option="null" fieldName="coAuthor" :multi="false" />
</a-form-item> </a-form-item>
<Field <Field :unchecked-value="false" :value="true" type="checkbox" name="completed" v-slot="{ value, field, errorMessage }">
:unchecked-value="false"
:value="true"
type="checkbox"
name="completed"
v-slot="{ value, field, errorMessage }"
>
<a-checkbox v-bind="field"> Complete </a-checkbox> <a-checkbox v-bind="field"> Complete </a-checkbox>
</Field> </Field>
<a-divider /> <a-divider />
@ -125,11 +92,7 @@
if (e.moved) { if (e.moved) {
// log.debug(e.moved); // log.debug(e.moved);
move(e.moved.oldIndex, e.moved.newIndex); move(e.moved.oldIndex, e.moved.newIndex);
acData.chapters = lmove( acData.chapters = lmove(acData.chapters, e.moved.oldIndex, e.moved.newIndex);
acData.chapters,
e.moved.oldIndex,
e.moved.newIndex,
);
// log.debug(toRaw(acData.chapters.map((a) => toRaw(a)))); // log.debug(toRaw(acData.chapters.map((a) => toRaw(a))));
} }
} }
@ -194,16 +157,8 @@
</template> </template>
</draggable> </draggable>
</field-array> </field-array>
<a-button type="primary" html-type="submit">{{ <a-button type="primary" html-type="submit">{{ submitText || "Post" }}</a-button>
submitText || "Post" <a-button html-type="submit" v-if="canDraft" @click="() => (otherBtnInvoked = true)"> Save for Later </a-button>
}}</a-button>
<a-button
html-type="submit"
v-if="canDraft"
@click="() => (otherBtnInvoked = true)"
>
Save for Later
</a-button>
</form> </form>
<!-- </vee-form> --> <!-- </vee-form> -->
</template> </template>

@ -1,11 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { import { useField } from "vee-validate";
Form as VeeForm,
Field as veeField,
useForm,
useField,
ErrorMessage,
} from "vee-validate";
import { story } from "@client/editorConfig"; import { story } from "@client/editorConfig";
import icon from "~/components/icon.vue"; import icon from "~/components/icon.vue";
import baseEditor from "../../baseEditor.vue"; import baseEditor from "../../baseEditor.vue";
@ -22,12 +16,7 @@
</a-radio-group> </a-radio-group>
<br /> <br />
<br /> <br />
<base-editor <base-editor label="" v-if="pvalue === 'pasteOrType'" :init="story" :name="fname + 'content'" />
label=""
v-if="pvalue === 'pasteOrType'"
:init="story"
:name="fname + 'content'"
/>
<a-upload <a-upload
v-model:file-list="fileList" v-model:file-list="fileList"
v-else-if="pvalue === 'upload'" v-else-if="pvalue === 'upload'"
@ -53,10 +42,6 @@
} }
" "
> >
<a-button type="primary"> <a-button type="primary"> <icon istyle="regular" name="upload" /><span style="margin-left: 0.5em"> Upload a file</span> </a-button>
<icon istyle="regular" name="upload" /><span style="margin-left: 0.5em">
Upload a file</span
>
</a-button>
</a-upload> </a-upload>
</template> </template>

@ -1,5 +1,4 @@
import { AsyncData, UseFetchOptions } from "#app"; import { AsyncData } from "#app";
import { NitroFetchRequest } from "nitropack";
const useApiFetch = async <T>(url: string, options?: any) => { const useApiFetch = async <T>(url: string, options?: any) => {
// const { token } = useAuth(); // const { token } = useAuth();

@ -4,7 +4,7 @@
import cfooter from "~/components/layouts/footer.vue"; import cfooter from "~/components/layouts/footer.vue";
import sidebarThing from "~/components/layouts/sidebar.vue"; import sidebarThing from "~/components/layouts/sidebar.vue";
import icon from "~/components/icon.vue"; import icon from "~/components/icon.vue";
import { ISidebarItem } from "@models/sidebarEntry";
const { useToken } = theme; const { useToken } = theme;
const { token } = useToken(); const { token } = useToken();
@ -52,10 +52,7 @@
<div class="stat-block"> <div class="stat-block">
<div> <div>
<a-typography-text> Band fiction that rocks </a-typography-text> <a-typography-text> Band fiction that rocks </a-typography-text>
<a-typography-text type="secondary"> <a-typography-text type="secondary"> With {{ totals?.stories ?? 0 }} stories by {{ totals?.authors ?? 0 }} authors </a-typography-text>
With {{ totals?.stories ?? 0 }} stories by
{{ totals?.authors ?? 0 }} authors
</a-typography-text>
</div> </div>
</div> </div>
<navbar /> <navbar />

@ -1,39 +1,20 @@
import * as yup from "yup"; import * as yup from "yup";
import { FormChapter, FormStory } from "./types/form/story"; import { FormChapter } from "./types/form/story";
const emptySummary = "Summary cannot be blank"; const emptySummary = "Summary cannot be blank";
const emptyChapterTitle = "Chapter title cannot be blank."; const emptyChapterTitle = "Chapter title cannot be blank.";
const blankTitle = "Title cannot be blank."; const blankTitle = "Title cannot be blank.";
export const cs = yup.object<FormChapter>().shape({ export const cs = yup.object<FormChapter>().shape({
chapterTitle: yup chapterTitle: yup.string().ensure().min(1, emptyChapterTitle).trim(emptyChapterTitle).required(emptyChapterTitle),
.string()
.ensure()
.min(1, emptyChapterTitle)
.trim(emptyChapterTitle)
.required(emptyChapterTitle),
summary: yup.string().ensure().min(10, emptySummary).required(emptySummary), summary: yup.string().ensure().min(10, emptySummary).required(emptySummary),
notes: yup.string().ensure(), notes: yup.string().ensure(),
bands: yup bands: yup.array().ensure().of(yup.number()).min(1, "One or more bands must be selected."),
.array() characters: yup.array().ensure().min(1, "One or more characters must be selected"),
.ensure()
.of(yup.number())
.min(1, "One or more bands must be selected."),
characters: yup
.array()
.ensure()
.min(1, "One or more characters must be selected"),
relationships: yup relationships: yup
.array() .array()
.ensure() .ensure()
.of( .of(yup.array().ensure().of(yup.string()).min(2, "Pairings must have at least two characters!").max(3, "Pairings can have no more than three characters!")),
yup
.array()
.ensure()
.of(yup.string())
.min(2, "Pairings must have at least two characters!")
.max(3, "Pairings can have no more than three characters!"),
),
nsfw: yup.boolean().oneOf([true, false]), nsfw: yup.boolean().oneOf([true, false]),
loggedInOnly: yup.boolean().when("nsfw", ([nsfw], schema) => { loggedInOnly: yup.boolean().when("nsfw", ([nsfw], schema) => {
return nsfw return nsfw
@ -44,20 +25,13 @@ export const cs = yup.object<FormChapter>().shape({
: schema.oneOf([true, false]); : schema.oneOf([true, false]);
}), }),
hidden: yup.boolean().oneOf([true, false]), hidden: yup.boolean().oneOf([true, false]),
pot: yup pot: yup.string().oneOf(["pasteOrType", "upload"]).required("Story content is required!"),
.string()
.oneOf(["pasteOrType", "upload"])
.required("Story content is required!"),
storytext: yup.string().when("pot", ([pot], schema) => { storytext: yup.string().when("pot", ([pot], schema) => {
return pot === "pasteOrType" return pot === "pasteOrType"
? schema ? schema
.test( .test("numWords", "Story must be at least 50 words", (value: any, context) => {
"numWords", return value?.split(/\W+/).length > 50 || false;
"Story must be at least 50 words", })
(value: any, context) => {
return value?.split(/\W+/).length > 50 || false;
},
)
.required("Story text can't be blank!") .required("Story text can't be blank!")
: schema.min(0); : schema.min(0);
}), }),
@ -98,10 +72,6 @@ export const cs = yup.object<FormChapter>().shape({
export const storySchema = yup.object().shape({ export const storySchema = yup.object().shape({
title: yup.string().ensure().min(5, blankTitle).required(blankTitle), title: yup.string().ensure().min(5, blankTitle).required(blankTitle),
chapters: yup chapters: yup.array().min(1, "There must be at least one chapter.").of(cs).ensure(),
.array()
.min(1, "There must be at least one chapter.")
.of(cs)
.ensure(),
completed: yup.boolean().oneOf([true, false]), completed: yup.boolean().oneOf([true, false]),
}); });

@ -1,5 +1,3 @@
import { readFileSync } from "fs";
import { resolve } from "path";
// import chardet from "chardet"; // import chardet from "chardet";
// import iconv from "iconv-lite"; // import iconv from "iconv-lite";
import { GridFSBucketReadStream } from "mongodb"; import { GridFSBucketReadStream } from "mongodb";
@ -15,20 +13,13 @@ export function countWords(string: string) {
return stripHtml(string).result.split(/W+/).length; return stripHtml(string).result.split(/W+/).length;
} }
export function populate<T>( export function populate<T>(field: string, model: string): PreMiddlewareFunction<Query<T, T>> {
field: string,
model: string,
): PreMiddlewareFunction<Query<T, T>> {
return function (next: () => any) { return function (next: () => any) {
this.populate(field, undefined, model); this.populate(field, undefined, model);
next(); next();
}; };
} }
export function populateSelected<T>( export function populateSelected<T>(field: string, model: string, selection: string): PreMiddlewareFunction<Query<T, T>> {
field: string,
model: string,
selection: string,
): PreMiddlewareFunction<Query<T, T>> {
return function (next: () => any) { return function (next: () => any) {
this.populate(field, selection, model); this.populate(field, selection, model);
next(); next();
@ -40,15 +31,11 @@ export function isFicmasHidden(story: IStory): boolean {
((story.ficmas as IFicmas)?.year == new Date().getFullYear() && ((story.ficmas as IFicmas)?.year == new Date().getFullYear() &&
(story.ficmas as IFicmas)?.anniversary && (story.ficmas as IFicmas)?.anniversary &&
new Date() < new Date(Date.parse("Aug 1 " + new Date().getFullYear()))) || new Date() < new Date(Date.parse("Aug 1 " + new Date().getFullYear()))) ||
((story.ficmas as IFicmas)?.year == new Date().getFullYear() && ((story.ficmas as IFicmas)?.year == new Date().getFullYear() && !(story.ficmas as IFicmas)?.anniversary && ficsHidden(Date.now()))
!(story.ficmas as IFicmas)?.anniversary &&
ficsHidden(Date.now()))
); );
} }
export function stringifyStream( export function stringifyStream(stream: GridFSBucketReadStream): Promise<string> {
stream: GridFSBucketReadStream,
): Promise<string> {
let chunks: Buffer[] = []; let chunks: Buffer[] = [];
return new Promise((res, rej) => { return new Promise((res, rej) => {
stream.on("data", (c) => chunks.push(Buffer.from(c))); stream.on("data", (c) => chunks.push(Buffer.from(c)));

@ -1,6 +1,5 @@
import { H3Event, EventHandlerRequest } from "h3"; import { H3Event, EventHandlerRequest } from "h3";
import { GridFSBucket } from "mongodb"; import { Document } from "mongoose";
import mongoose, { Document } from "mongoose";
import { norm, stringifyStream } from "@functions"; import { norm, stringifyStream } from "@functions";
import { IStory } from "@models/stories"; import { IStory } from "@models/stories";
import { IChapter } from "@models/stories/chapter"; import { IChapter } from "@models/stories/chapter";
@ -16,11 +15,7 @@ export default async function (
const cloned: any & { chapters: IChapter[] } = { ...finObj }; const cloned: any & { chapters: IChapter[] } = { ...finObj };
delete finObj.chapters; delete finObj.chapters;
const bucket = getBucket(); const bucket = getBucket();
let ds = bucket.openDownloadStreamByName( let ds = bucket.openDownloadStreamByName(`/stories/${cloned.chapters[cindex || event.context.chapterIndex || 0].id}.txt`);
`/stories/${
cloned.chapters[cindex || event.context.chapterIndex || 0].id
}.txt`,
);
let stream = await stringifyStream(ds); let stream = await stringifyStream(ds);
finObj.currentChapter = { finObj.currentChapter = {
...cloned.chapters[cindex || event.context.chapterIndex || 0], ...cloned.chapters[cindex || event.context.chapterIndex || 0],

@ -1,4 +1,3 @@
import { Band } from "@models/band";
import { Challenge } from "@models/challenges/gen"; import { Challenge } from "@models/challenges/gen";
import { IStory, Story } from "@models/stories"; import { IStory, Story } from "@models/stories";
import { log } from "../logger"; import { log } from "../logger";

@ -1,16 +1,12 @@
import { H3Event, EventHandlerRequest } from "h3";
import { apiRoot } from "./constants"; import { apiRoot } from "./constants";
export default async function (id: number): Promise<number> { export default async function (id: number): Promise<number> {
let { data: lookup } = await useFetch<any>( let { data: lookup } = await useFetch<any>(`${apiRoot}/session-sharing/lookup`, {
`${apiRoot}/session-sharing/lookup`, method: "get",
{ query: {
method: "get", params: {
query: { id,
params: {
id,
},
}, },
}, },
); });
return lookup.value.uid as number; return lookup.value.uid as number;
} }

@ -1,12 +1,10 @@
import winston from "winston"; import winston from "winston";
const { combine, timestamp, json, splat, printf, colorize } = winston.format; const { combine, timestamp, json, splat, printf, colorize } = winston.format;
winston.add; // winston.add;
const fmt = printf(({ timestamp, level, message, label, durationMs }) => { const fmt = printf(({ timestamp, level, message, label, durationMs }) => {
return `${timestamp} [${label || "misc"}] ${message} ${ return `${timestamp} [${label || "misc"}] ${message} ${!!durationMs ? " (took " + durationMs + "ms)" : ""}`;
!!durationMs ? " (took " + durationMs + "ms)" : ""
}`;
}); });
const cfmt = combine(json(), timestamp(), fmt); const cfmt = combine(json(), timestamp(), fmt);

@ -2,7 +2,6 @@ import { EventHandlerRequest, H3Event } from "h3";
import { messages } from "@server/constants"; import { messages } from "@server/constants";
import { IStory } from "@models/stories"; import { IStory } from "@models/stories";
import { isFicmasHidden } from "@functions"; import { isFicmasHidden } from "@functions";
import { IDraft } from "@models/stories/draft";
import axios from "axios"; import axios from "axios";
import { IUser } from "@models/user"; import { IUser } from "@models/user";
export function isIdNan(ev: H3Event<EventHandlerRequest>) { export function isIdNan(ev: H3Event<EventHandlerRequest>) {
@ -33,11 +32,7 @@ export function isLoggedIn(ev: H3Event<EventHandlerRequest>) {
} }
} }
export async function storyCheck( export async function storyCheck(event: H3Event<EventHandlerRequest>, story: IStory, idx: number) {
event: H3Event<EventHandlerRequest>,
story: IStory,
idx: number,
) {
let ret: any = {}; let ret: any = {};
if (!story) { if (!story) {
ret.statusCode = 404; ret.statusCode = 404;
@ -49,11 +44,7 @@ export async function storyCheck(
message: `TOP SECRET! This story is part of an ongoing challenge. You'll be able to read it after the challenge's reveal date.`, message: `TOP SECRET! This story is part of an ongoing challenge. You'll be able to read it after the challenge's reveal date.`,
}; };
} }
} else if ( } else if (story.chapters[idx]?.hidden && event.context.currentUser?._id !== (story.author as IUser)._id && !event.context.currentUser?.profile.isAdmin) {
story.chapters[idx]?.hidden &&
event.context.currentUser?._id !== (story.author as IUser)._id &&
!event.context.currentUser?.profile.isAdmin
) {
ret.statusCode = 403; ret.statusCode = 403;
ret.message = messages[403]; ret.message = messages[403];
} }

@ -1,4 +1,4 @@
import mongoose, { connect, Document, Model } from "mongoose"; import mongoose, { Model } from "mongoose";
const { Schema, model } = mongoose; const { Schema, model } = mongoose;
import SequenceFactory from "mongoose-sequence"; import SequenceFactory from "mongoose-sequence";
import { hasMigrated } from "@dbconfig"; import { hasMigrated } from "@dbconfig";
@ -30,11 +30,5 @@ const BandSchema = new mongoose.Schema<IBand>({
], ],
}); });
hasMigrated && hasMigrated && !mongoose.models.Band && BandSchema.plugin(AutoIncrement, { id: "band" });
!mongoose.models.Band && export const Band: Model<IBand> = /* mongoose.models.Band || */ model<IBand>("Band", BandSchema, "bands");
BandSchema.plugin(AutoIncrement, { id: "band" });
export const Band: Model<IBand> = /* mongoose.models.Band || */ model<IBand>(
"Band",
BandSchema,
"bands",
);

@ -1,4 +1,4 @@
import mongoose, { Schema, PopulatedDoc, Document, Model } from "mongoose"; import mongoose, { PopulatedDoc, Model } from "mongoose";
import { IUser } from "@models/user"; import { IUser } from "@models/user";
import SequenceFactory from "mongoose-sequence"; import SequenceFactory from "mongoose-sequence";
import { hasMigrated } from "@dbconfig"; import { hasMigrated } from "@dbconfig";
@ -67,8 +67,5 @@ const biffnoschema = new mongoose.Schema<IBiffno>({
}, },
}); });
hasMigrated && hasMigrated && !mongoose.models.Biffno && biffnoschema.plugin(AutoIncrement, { start_seq: 1, id: "bif_id" });
!mongoose.models.Biffno && export const Biffno: Model<IBiffno> = mongoose.models.Biffno || mongoose.model("Biffno", biffnoschema, "biffno");
biffnoschema.plugin(AutoIncrement, { start_seq: 1, id: "bif_id" });
export const Biffno: Model<IBiffno> =
mongoose.models.Biffno || mongoose.model("Biffno", biffnoschema, "biffno");

@ -1,10 +1,4 @@
import mongoose, { import mongoose, { PopulatedDoc, Model, model } from "mongoose";
Schema,
PopulatedDoc,
Document,
Model,
model,
} from "mongoose";
import { IBand } from "@models/band"; import { IBand } from "@models/band";
import { IUser } from "@models/user"; import { IUser } from "@models/user";
@ -48,9 +42,6 @@ export const FicmasSchema = new mongoose.Schema<IFicmas>({
}, },
}); });
hasMigrated && hasMigrated && !mongoose.models.Ficmas && FicmasSchema.plugin(AutoIncrement, { id: "ficmas_wishes", inc_field: "_id" });
!mongoose.models.Ficmas &&
FicmasSchema.plugin(AutoIncrement, { id: "ficmas_wishes", inc_field: "_id" });
export const Ficmas: Model<IFicmas> = export const Ficmas: Model<IFicmas> = mongoose.models.Ficmas || model("Ficmas", FicmasSchema, "ficmas_wishes");
mongoose.models.Ficmas || model("Ficmas", FicmasSchema, "ficmas_wishes");

@ -1,4 +1,4 @@
import mongoose, { Schema, PopulatedDoc, Document, Model } from "mongoose"; import mongoose, { Model } from "mongoose";
import SequenceFactory from "mongoose-sequence"; import SequenceFactory from "mongoose-sequence";
import { hasMigrated } from "@dbconfig"; import { hasMigrated } from "@dbconfig";
@ -45,9 +45,7 @@ const challengeSchema = new mongoose.Schema<IChallenge>({
}, },
}); });
hasMigrated && hasMigrated && !mongoose.models.Challenge && challengeSchema.plugin(AutoIncrement, { id: "challenges" });
!mongoose.models.Challenge &&
challengeSchema.plugin(AutoIncrement, { id: "challenges" });
export const Challenge: Model<IChallenge> = export const Challenge: Model<IChallenge> =
// mongoose.models.Challenge || // mongoose.models.Challenge ||
mongoose.model("Challenge", challengeSchema, "challenges"); mongoose.model("Challenge", challengeSchema, "challenges");

@ -1,11 +1,4 @@
import mongoose, { import mongoose, { Schema, PopulatedDoc, Model } from "mongoose";
Schema,
connect,
PopulatedDoc,
Document,
Model,
} from "mongoose";
import SequenceFactory from "mongoose-sequence";
import { IPrivMsg } from "./privMsg"; import { IPrivMsg } from "./privMsg";
import { IUser } from "./user"; import { IUser } from "./user";
@ -41,8 +34,4 @@ const InboxSchema = new Schema<IInbox>({
], ],
}); });
export const Inbox: Model<IInbox> = mongoose.model<IInbox>( export const Inbox: Model<IInbox> = mongoose.model<IInbox>("Inbox", InboxSchema, "inboxes");
"Inbox",
InboxSchema,
"inboxes",
);

@ -1,4 +1,4 @@
import mongoose, { Schema, PopulatedDoc, Document, Model } from "mongoose"; import mongoose, { PopulatedDoc, Model } from "mongoose";
import SequenceFactory from "mongoose-sequence"; import SequenceFactory from "mongoose-sequence";
import { hasMigrated } from "@dbconfig"; import { hasMigrated } from "@dbconfig";
import { IUser } from "./user"; import { IUser } from "./user";
@ -50,13 +50,6 @@ const PMSchema = new mongoose.Schema<IPrivMsg>({
}, },
}); });
hasMigrated && hasMigrated && !mongoose.models.PrivMsg && PMSchema.plugin(AutoIncrement, { id: "private_message" });
!mongoose.models.PrivMsg &&
PMSchema.plugin(AutoIncrement, { id: "private_message" });
export const PrivMsg: Model<IPrivMsg> = export const PrivMsg: Model<IPrivMsg> = /* mongoose.models.PrivMsg || */ mongoose.model("PrivMsg", PMSchema, "private_messages");
/* mongoose.models.PrivMsg || */ mongoose.model(
"PrivMsg",
PMSchema,
"private_messages",
);

@ -1,4 +1,4 @@
import mongoose, { connect, PopulatedDoc, Document } from "mongoose"; import mongoose from "mongoose";
const { Schema, model } = mongoose; const { Schema, model } = mongoose;
interface IAbstractQM { interface IAbstractQM {

@ -1,4 +1,4 @@
import mongoose, { Schema, PopulatedDoc, Document, Model } from "mongoose"; import mongoose, { Model } from "mongoose";
export enum Color { export enum Color {
"orange" = "orange", "orange" = "orange",
@ -35,9 +35,4 @@ const SISchema = new mongoose.Schema<ISidebarItem>({
}); });
export const SidebarItem: Model<ISidebarItem> = export const SidebarItem: Model<ISidebarItem> =
mongoose.models.SidebarItem || mongoose.models.SidebarItem || /* mongoose.models.SidebarItem || */ mongoose.model("SidebarItem", SISchema, "sidebar");
/* mongoose.models.SidebarItem || */ mongoose.model(
"SidebarItem",
SISchema,
"sidebar",
);

@ -1,4 +1,4 @@
import { Schema, PopulatedDoc, Document, Model } from "mongoose"; import { Schema, PopulatedDoc } from "mongoose";
import { IBand } from "@models/band"; import { IBand } from "@models/band";
export interface IChapter { export interface IChapter {
title: string; title: string;

@ -1,19 +1,12 @@
import { IStory } from "."; import { IStory } from ".";
import { hasMigrated } from "@dbconfig"; import { hasMigrated } from "@dbconfig";
import { IBand } from "@models/band"; import mongoose, { Schema, Model } from "mongoose";
import { IFicmas } from "@models/challenges/ficmas";
import { IChallenge } from "@models/challenges/gen";
import { IUser } from "@models/user";
import mongoose, { Schema, PopulatedDoc, Document, Model } from "mongoose";
import SequenceFactory from "mongoose-sequence"; import SequenceFactory from "mongoose-sequence";
import { Chapter } from "./chapter"; import { Chapter } from "./chapter";
const AutoIncrement = SequenceFactory(mongoose); const AutoIncrement = SequenceFactory(mongoose);
export type IDraft = Omit< export type IDraft = Omit<IStory, "recs" | "favs" | "reviews" | "views" | "downloads" | "posted">;
IStory,
"recs" | "favs" | "reviews" | "views" | "downloads" | "posted"
>;
// const Cha // const Cha
@ -39,9 +32,6 @@ const DraftSchema = new Schema<IDraft>(
{ timestamps: true }, { timestamps: true },
); );
hasMigrated && hasMigrated && !mongoose.models.Draft && DraftSchema.plugin(AutoIncrement, { id: "drafts" });
!mongoose.models.Draft &&
DraftSchema.plugin(AutoIncrement, { id: "drafts" });
export const Draft: Model<IDraft> = export const Draft: Model<IDraft> = /* mongoose.models.Draft || */ mongoose.model("Draft", DraftSchema, "drafts");
/* mongoose.models.Draft || */ mongoose.model("Draft", DraftSchema, "drafts");

@ -1,4 +1,4 @@
import mongoose, { Schema, PopulatedDoc, Document, Model } from "mongoose"; import mongoose, { PopulatedDoc, Model } from "mongoose";
import SequenceFactory from "mongoose-sequence"; import SequenceFactory from "mongoose-sequence";
const AutoIncrement = SequenceFactory(mongoose); const AutoIncrement = SequenceFactory(mongoose);
@ -87,13 +87,6 @@ const StorySchema = new mongoose.Schema<IStory>({
default: new Date(), default: new Date(),
}, },
}); });
hasMigrated && hasMigrated && !mongoose.models.Story && Chapter.plugin(AutoIncrement, { id: "chapterid", inc_field: "id" });
!mongoose.models.Story &&
Chapter.plugin(AutoIncrement, { id: "chapterid", inc_field: "id" });
hasMigrated && StorySchema.plugin(AutoIncrement, { id: "storyid" }); hasMigrated && StorySchema.plugin(AutoIncrement, { id: "storyid" });
export const Story: Model<IStory> = export const Story: Model<IStory> = /* mongoose.models.Story || */ mongoose.model("Story", StorySchema, "stories");
/* mongoose.models.Story || */ mongoose.model(
"Story",
StorySchema,
"stories",
);

@ -1,4 +1,4 @@
import mongoose, { Schema, PopulatedDoc, Document, Model } from "mongoose"; import mongoose, { PopulatedDoc, Model } from "mongoose";
import SequenceFactory from "mongoose-sequence"; import SequenceFactory from "mongoose-sequence";
import { hasMigrated } from "@dbconfig"; import { hasMigrated } from "@dbconfig";
import { populate, populateSelected } from "@functions"; import { populate, populateSelected } from "@functions";
@ -63,22 +63,9 @@ CommentSchema
// .pre("find", populateSelected("replyingTo", modelName, "-replies -author")) // .pre("find", populateSelected("replyingTo", modelName, "-replies -author"))
.pre("findOne", populate("replies", modelName)) .pre("findOne", populate("replies", modelName))
.pre("find", populate("replies", modelName)) .pre("find", populate("replies", modelName))
.pre( .pre("findOne", populateSelected("author", "User", "profile username _id blocked"))
"findOne", .pre("find", populateSelected("author", "User", "profile username _id blocked"));
populateSelected("author", "User", "profile username _id blocked"),
)
.pre(
"find",
populateSelected("author", "User", "profile username _id blocked"),
);
hasMigrated && hasMigrated && !mongoose.models.Review && CommentSchema.plugin(AutoIncrement, { id: "reviews" });
!mongoose.models.Review &&
CommentSchema.plugin(AutoIncrement, { id: "reviews" });
export const Review: Model<IReview> = export const Review: Model<IReview> = /* mongoose.models.Review || */ mongoose.model(modelName, CommentSchema, "reviews");
/* mongoose.models.Review || */ mongoose.model(
modelName,
CommentSchema,
"reviews",
);

@ -1,10 +1,4 @@
import mongoose, { import mongoose, { PopulatedDoc, Document, Model } from "mongoose";
Schema,
connect,
PopulatedDoc,
Document,
Model,
} from "mongoose";
import SequenceFactory from "mongoose-sequence"; import SequenceFactory from "mongoose-sequence";
import bcrypt from "bcryptjs"; import bcrypt from "bcryptjs";
import md5 from "blueimp-md5"; import md5 from "blueimp-md5";
@ -274,25 +268,15 @@ UserSchema.static("generateHash", function (password: string): string {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8)); return bcrypt.hashSync(password, bcrypt.genSaltSync(8));
}); });
UserSchema.methods.validPassword = function (password: string): boolean { UserSchema.methods.validPassword = function (password: string): boolean {
return ( return md5(password) === this.password || bcrypt.compareSync(password, this.password) || false;
md5(password) === this.password ||
bcrypt.compareSync(password, this.password) ||
false
);
}; };
UserSchema.methods.generateJWT = function (jwtKey: string): string { UserSchema.methods.generateJWT = function (jwtKey: string): string {
let token = jwt.sign( let token = jwt.sign({ id: this._id, isAdmin: this.profile.isAdmin }, jwtKey, {
{ id: this._id, isAdmin: this.profile.isAdmin }, expiresIn: "14 days",
jwtKey, });
{
expiresIn: "14 days",
},
);
return token; return token;
}; };
hasMigrated && hasMigrated && !mongoose.models.User && UserSchema.plugin(AutoIncrement, { id: "userid", inc_field: "_id" });
!mongoose.models.User &&
UserSchema.plugin(AutoIncrement, { id: "userid", inc_field: "_id" });
export const User = mongoose.model<IUser, UModel>("User", UserSchema, "users"); export const User = mongoose.model<IUser, UModel>("User", UserSchema, "users");

@ -1,6 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive } from "vue"; import { reactive } from "vue";
import useApiFetch from "../../composables/useApiFetch";
import { notification } from "ant-design-vue"; import { notification } from "ant-design-vue";
interface FormState { interface FormState {
username: string; username: string;
@ -38,28 +37,11 @@
}; };
</script> </script>
<template> <template>
<a-form <a-form :model="formState" name="basic" :label-col="{ span: 8 }" autocomplete="off" :colon="false" layout="vertical" @finish="onFinish">
:model="formState" <a-form-item label="Username" name="username" :rules="[{ required: true, message: 'Username required!' }]">
name="basic"
:label-col="{ span: 8 }"
autocomplete="off"
:colon="false"
layout="vertical"
@finish="onFinish"
>
<a-form-item
label="Username"
name="username"
:rules="[{ required: true, message: 'Username required!' }]"
>
<a-input v-model:value="formState.username" /> <a-input v-model:value="formState.username" />
</a-form-item> </a-form-item>
<a-form-item <a-form-item :colon="false" label="Password" name="password" :rules="[{ required: true, message: 'Password required!' }]">
:colon="false"
label="Password"
name="password"
:rules="[{ required: true, message: 'Password required!' }]"
>
<a-input-password v-model:value="formState.password" /> <a-input-password v-model:value="formState.password" />
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>

@ -1,21 +1,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive } from "vue"; import { Field as veeField, useField, useForm } from "vee-validate";
import {
Form as veeForm,
Field as veeField,
useField,
useForm,
useSetFieldValue,
useFormErrors,
useFormValues,
RuleExpression,
} from "vee-validate";
import * as yup from "yup"; import * as yup from "yup";
import { useRecaptchaProvider } from "vue-recaptcha"; import { useRecaptchaProvider } from "vue-recaptcha";
import { useChallengeV2 } from "vue-recaptcha"; import { useChallengeV2 } from "vue-recaptcha";
import { notification } from "ant-design-vue"; import { notification } from "ant-design-vue";
import { log } from "@server/logger";
import termsOfServices from "~/components/tos.vue"; import termsOfServices from "~/components/tos.vue";
useRecaptchaProvider(); useRecaptchaProvider();
@ -34,24 +23,11 @@
}); });
// const { execute } = useChallengeV3('submit'); // const { execute } = useChallengeV3('submit');
const vschema = yup.object<FormState>().shape({ const vschema = yup.object<FormState>().shape({
username: yup username: yup.string().ensure().trim().min(1).required("Username is required!"),
.string() password: yup.string().ensure().trim().min(8).required("Password is required!"),
.ensure()
.trim()
.min(1)
.required("Username is required!"),
password: yup
.string()
.ensure()
.trim()
.min(8)
.required("Password is required!"),
email: yup.string().ensure().trim().email().required("Email is required!"), email: yup.string().ensure().trim().email().required("Email is required!"),
// recaptcha: yup.string().required('Please verify you are human.'), // recaptcha: yup.string().required('Please verify you are human.'),
agree: yup agree: yup.boolean().oneOf([true], "Please agree to the terms.").required("Please agree to the terms."),
.boolean()
.oneOf([true], "Please agree to the terms.")
.required("Please agree to the terms."),
}); });
const dv: FormState = { const dv: FormState = {
username: "", username: "",
@ -120,48 +96,26 @@ notification[ "error" ]({
<template> <template>
<form @submit="onFinish"> <form @submit="onFinish">
<vee-field name="username" v-slot="{ field, errorMessage, value }"> <vee-field name="username" v-slot="{ field, errorMessage, value }">
<a-form-item <a-form-item label="Username" :name="field.name" :validate-status="!!errorMessage ? 'error' : ''" :help="errorMessage">
label="Username"
:name="field.name"
:validate-status="!!errorMessage ? 'error' : ''"
:help="errorMessage"
>
<a-input v-bind="field" v-model:value="field.value" /> <a-input v-bind="field" v-model:value="field.value" />
</a-form-item> </a-form-item>
</vee-field> </vee-field>
<vee-field name="email" v-slot="{ field, errorMessage, value }"> <vee-field name="email" v-slot="{ field, errorMessage, value }">
<a-form-item <a-form-item label="Email address" :name="field.name" :validate-status="!!errorMessage ? 'error' : ''" :help="errorMessage">
label="Email address"
:name="field.name"
:validate-status="!!errorMessage ? 'error' : ''"
:help="errorMessage"
>
<a-input v-bind="field" v-model:value="field.value" /> <a-input v-bind="field" v-model:value="field.value" />
</a-form-item> </a-form-item>
</vee-field> </vee-field>
<vee-field name="password" v-slot="{ field, errorMessage, value }"> <vee-field name="password" v-slot="{ field, errorMessage, value }">
<a-form-item <a-form-item label="Password" :name="field.name" :validate-status="!!errorMessage ? 'error' : ''" :help="errorMessage">
label="Password"
:name="field.name"
:validate-status="!!errorMessage ? 'error' : ''"
:help="errorMessage"
>
<a-input-password v-bind="field" v-model:value="field.value" /> <a-input-password v-bind="field" v-model:value="field.value" />
</a-form-item> </a-form-item>
</vee-field> </vee-field>
<a-typography-title :level="4" :style="{ textAlign: 'center' }" <a-typography-title :level="4" :style="{ textAlign: 'center' }">Terms</a-typography-title>
>Terms</a-typography-title
>
<div class="maxHeightScroller"> <div class="maxHeightScroller">
<div style="height: 100%"> <div style="height: 100%">
<terms-of-services /> <terms-of-services />
<vee-field <vee-field name="agree" :unchecked-value="false" type="checkbox" v-slot="{ field, value, errorMessage }">
name="agree"
:unchecked-value="false"
type="checkbox"
v-slot="{ field, value, errorMessage }"
>
<a-checkbox <a-checkbox
@update:checked=" @update:checked="
(n) => { (n) => {
@ -179,9 +133,7 @@ notification[ "error" ]({
<div ref="root" /> <div ref="root" />
<a-row :align="'middle'" justify="center"> <a-row :align="'middle'" justify="center">
<a-col> <a-col>
<a-button size="large" type="primary" html-type="submit" <a-button size="large" type="primary" html-type="submit">Sign me up!</a-button>
>Sign me up!</a-button
>
</a-col> </a-col>
</a-row> </a-row>
</form> </form>

@ -1,6 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { IChapter } from "@models/stories/chapter";
import { IStory } from "@models/stories";
import { storyEditMiddleware } from "@client/middleware"; import { storyEditMiddleware } from "@client/middleware";
import { SingleChapterResult } from "@client/types/slightlyDifferentStory"; import { SingleChapterResult } from "@client/types/slightlyDifferentStory";
import SingleChapter from "~/components/story/create/singleChapter.vue"; import SingleChapter from "~/components/story/create/singleChapter.vue";
@ -13,9 +11,7 @@
const rtr = useRoute(); const rtr = useRoute();
const { const {
data: { value: originalStory }, data: { value: originalStory },
} = await useApiFetch<SingleChapterResult | null>( } = await useApiFetch<SingleChapterResult | null>(`/story/${rtr.params.id}/${rtr.params.cidx}`);
`/story/${rtr.params.id}/${rtr.params.cidx}`,
);
if (originalStory === null) { if (originalStory === null) {
throw createError({ throw createError({
statusCode: 404, statusCode: 404,
@ -28,8 +24,5 @@
</script> </script>
<template> <template>
<single-chapter <single-chapter :data="toFormChapter(originalStory!.currentChapter)" :name="originalStory!.currentChapter.title" />
:data="toFormChapter(originalStory!.currentChapter)"
:name="originalStory!.currentChapter.title"
/>
</template> </template>

@ -6,12 +6,12 @@
import { IChapter } from "@models/stories/chapter"; import { IChapter } from "@models/stories/chapter";
import { storyEditMiddleware } from "@client/middleware"; import { storyEditMiddleware } from "@client/middleware";
import { IBand } from "@models/band";
import { IUser } from "@models/user";
const rtr = useRoute(); const rtr = useRoute();
const { const {
data: { value: originalStory }, data: { value: originalStory },
} = await useApiFetch< } = await useApiFetch<({ chapters: (IChapter & { text: string })[] } & IStory) | null>(`/story/${rtr.params.id}/full`);
({ chapters: (IChapter & { text: string })[] } & IStory) | null
>(`/story/${rtr.params.id}/full`);
if (originalStory === null) { if (originalStory === null) {
console.log("IT DOESN'T EXIST DAWG"); console.log("IT DOESN'T EXIST DAWG");
throw createError({ throw createError({
@ -20,18 +20,18 @@
}); });
} }
definePageMeta({ definePageMeta({
middleware: [storyEditMiddleware, "auth"], middleware: ["auth", storyEditMiddleware],
}); });
const story: FormStory = { const story: FormStory = {
title: originalStory!.title, title: originalStory!.title,
coAuthor: originalStory?.coAuthor ? originalStory.coAuthor._id : null, coAuthor: originalStory?.coAuthor ? (originalStory.coAuthor as IUser)._id : null,
completed: originalStory!.completed, completed: originalStory!.completed,
chapters: originalStory!.chapters.map((a, i) => ({ chapters: originalStory!.chapters.map((a, i) => ({
...a, ...a,
id: a.id, id: a.id,
chapterTitle: a.title, chapterTitle: a.title,
index: i + 1, index: i + 1,
bands: a.bands.map((a) => a._id), bands: (a.bands as IBand[]).map((a) => a._id),
content: a.text, content: a.text,
uuidKey: v4(), uuidKey: v4(),
})), })),
@ -41,14 +41,6 @@
}); });
</script> </script>
<template> <template>
<a-typography-title style="text-align: center"> <a-typography-title style="text-align: center"> Editing "{{ originalStory?.title }}" </a-typography-title>
Editing "{{ originalStory?.title }}" <story-form :can-draft="false" :data="story" :endpoint="`/story/${rtr.params.id}`" endpoint-method="put"> </story-form>
</a-typography-title>
<story-form
:can-draft="false"
:data="story"
:endpoint="`/story/${rtr.params.id}`"
endpoint-method="put"
>
</story-form>
</template> </template>

@ -1,7 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { format, formatDistanceToNow, formatRelative } from "date-fns"; import { format, formatDistanceToNow } from "date-fns";
import { IUser } from "@models/user"; import { IUser } from "@models/user";
import { IStory } from "@models/stories";
import { favourites } from "@client/listActions"; import { favourites } from "@client/listActions";
import singleStory from "~/components/listings/singleStory.vue"; import singleStory from "~/components/listings/singleStory.vue";
import icon from "~/components/icon.vue"; import icon from "~/components/icon.vue";
@ -16,10 +15,7 @@
} }
const activeKey = ref("main"); const activeKey = ref("main");
const activeFavKey = ref("favs/stories"); const activeFavKey = ref("favs/stories");
const uLastVisit = Date.parse( const uLastVisit = Date.parse((userInfo.value?.lastVisit || userInfo.value?.lastLogin) as unknown as string);
(userInfo.value?.lastVisit ||
userInfo.value?.lastLogin) as unknown as string,
);
const isSelf = userInfo.value?._id === parseInt(rtr.params.id as string); const isSelf = userInfo.value?._id === parseInt(rtr.params.id as string);
useHead({ useHead({
@ -32,10 +28,7 @@
<div style="height: fit-content"> <div style="height: fit-content">
<a-card-meta style="align-items: center; margin: 0.5em"> <a-card-meta style="align-items: center; margin: 0.5em">
<template #avatar> <template #avatar>
<a-avatar <a-avatar :size="75" :src="`/avatars/${userInfo?.profile.avatar}.png`" />
:size="75"
:src="`/avatars/${userInfo?.profile.avatar}.png`"
/>
</template> </template>
<template #title> <template #title>
<a-typography-title :level="1" style="margin-top: 0.5em"> <a-typography-title :level="1" style="margin-top: 0.5em">
@ -48,15 +41,9 @@
<template #text> Administrator </template> <template #text> Administrator </template>
</a-badge-ribbon> </a-badge-ribbon>
</template> </template>
<a-descriptions <a-descriptions :column="2" :labelStyle="{ fontWeight: 'bold' }" :colon="false">
:column="2"
:labelStyle="{ fontWeight: 'bold' }"
:colon="false"
>
<a-descriptions-item label="Last visit"> <a-descriptions-item label="Last visit">
<div v-if="userInfo?.banned" style="color: red; font-weight: bold"> <div v-if="userInfo?.banned" style="color: red; font-weight: bold">BANNED</div>
BANNED
</div>
<div v-else-if="userInfo?.profile.hidden"> <div v-else-if="userInfo?.profile.hidden">
<i>Unknown</i> <i>Unknown</i>
</div> </div>
@ -64,38 +51,23 @@
<span> <span>
{{ format(uLastVisit, "MM/dd/yyyy @ hh:mm:ss a") }} {{ format(uLastVisit, "MM/dd/yyyy @ hh:mm:ss a") }}
</span> </span>
<span style="margin-left: 0.6em"> <span style="margin-left: 0.6em"> ({{ formatDistanceToNow(uLastVisit, { addSuffix: true }) }}) </span>
({{ formatDistanceToNow(uLastVisit, { addSuffix: true }) }})
</span>
</div> </div>
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item label="Website"> <a-descriptions-item label="Website">
<a <a target="_blank" :href="`${userInfo?.profile.website.startsWith('http') ? '' : 'http://'}${userInfo?.profile.website}`">
target="_blank"
:href="`${
userInfo?.profile.website.startsWith('http') ? '' : 'http://'
}${userInfo?.profile.website}`"
>
{{ userInfo?.profile.website }} {{ userInfo?.profile.website }}
</a> </a>
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item label="Blog/Journal"> <a-descriptions-item label="Blog/Journal">
<a <a target="_blank" :href="`${userInfo?.profile.blog.startsWith('http') ? '' : 'http://'}${userInfo?.profile.blog}`">
target="_blank"
:href="`${
userInfo?.profile.blog.startsWith('http') ? '' : 'http://'
}${userInfo?.profile.blog}`"
>
{{ userInfo?.profile.blog }} {{ userInfo?.profile.blog }}
</a> </a>
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item label="Occupation"> <a-descriptions-item label="Occupation">
{{ userInfo?.profile.occupation }} {{ userInfo?.profile.occupation }}
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item <a-descriptions-item label="Email" v-if="userInfo?.profile.showEmail || ses?.user?.profile.isAdmin">
label="Email"
v-if="userInfo?.profile.showEmail || ses?.user?.profile.isAdmin"
>
{{ userInfo?.email }} {{ userInfo?.email }}
</a-descriptions-item> </a-descriptions-item>
</a-descriptions> </a-descriptions>
@ -129,18 +101,7 @@
<single-story :last="true" :story="item" /> <single-story :last="true" :story="item" />
</a-col> </a-col>
<a-col :span="1" v-if="isSelf"> <a-col :span="1" v-if="isSelf">
<a <a style="color: red" @click="() => favourites(userInfo?.favs.stories || [], item._id, true, 'story')">
style="color: red"
@click="
() =>
favourites(
userInfo?.favs.stories || [],
item._id,
true,
'story',
)
"
>
<icon istyle="regular" name="trash" color="#f00" /> <icon istyle="regular" name="trash" color="#f00" />
</a> </a>
</a-col> </a-col>
@ -149,16 +110,10 @@
</a-list> </a-list>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="favs/authors" tab="Authors"> <a-tab-pane key="favs/authors" tab="Authors">
<a-list <a-list item-layout="horizontal" :data-source="userInfo?.favs.authors" :grid="{ gutter: 16, column: 3 }">
item-layout="horizontal"
:data-source="userInfo?.favs.authors"
:grid="{ gutter: 16, column: 3 }"
>
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item style="display: flex; align-items: center"> <a-list-item style="display: flex; align-items: center">
<a-list-item-meta <a-list-item-meta style="align-items: center; width: min-content">
style="align-items: center; width: min-content"
>
<template #avatar> <template #avatar>
<a-avatar :src="`/avatars/${item.profile.avatar}.png`" /> <a-avatar :src="`/avatars/${item.profile.avatar}.png`" />
</template> </template>
@ -170,18 +125,7 @@
</a-list-item-meta> </a-list-item-meta>
<template #actions v-if="isSelf"> <template #actions v-if="isSelf">
<span> <span>
<a <a style="color: red" @click="() => favourites(userInfo?.favs.authors || [], item._id, true, 'author')">
style="color: red"
@click="
() =>
favourites(
userInfo?.favs.authors || [],
item._id,
true,
'author',
)
"
>
<icon istyle="regular" name="trash" color="#f00" /> <icon istyle="regular" name="trash" color="#f00" />
</a> </a>
</span> </span>

@ -1,5 +1,3 @@
import mongoose from "mongoose";
import * as net from "net";
import plugnplay from "@server/plugnplay"; import plugnplay from "@server/plugnplay";
export default defineNuxtPlugin({ export default defineNuxtPlugin({
name: "mongo", name: "mongo",

@ -1,6 +1,6 @@
import mongoose from "mongoose"; import mongoose from "mongoose";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import { IUser, User } from "@models/user"; import { User } from "@models/user";
import { log } from "@server/logger"; import { log } from "@server/logger";
export default eventHandler(async (event) => { export default eventHandler(async (event) => {
@ -25,8 +25,7 @@ export default eventHandler(async (event) => {
if (!user.auth.emailVerified) { if (!user.auth.emailVerified) {
throw createError({ throw createError({
statusCode: 401, statusCode: 401,
message: message: 'Account inactive!<br><a href="/activate/resend">Resend verification</a>?',
'Account inactive!<br><a href="/activate/resend">Resend verification</a>?',
}); });
} }
let tok = user.generateJWT(useRuntimeConfig().jwt); let tok = user.generateJWT(useRuntimeConfig().jwt);

@ -1,11 +1,5 @@
import jwt from "jsonwebtoken";
import { log } from "@server/logger";
export default eventHandler((event) => { export default eventHandler((event) => {
let ahead = ( let ahead = (getHeaders(event).authorization || getCookie(event, "auth:token") || "")?.replace("Bearer ", "");
getHeaders(event).authorization ||
getCookie(event, "auth:token") ||
""
)?.replace("Bearer ", "");
if (event.context.currentUser) { if (event.context.currentUser) {
return { return {
token: ahead, token: ahead,

@ -1,6 +1,5 @@
import { messages } from "@server/constants"; import { messages } from "@server/constants";
import { isAdmin } from "@server/middlewareButNotReally"; import { isAdmin } from "@server/middlewareButNotReally";
import { isLoggedIn } from "@server/middlewareButNotReally";
import { Band, IBand } from "@models/band"; import { Band, IBand } from "@models/band";
export default eventHandler(async (ev) => { export default eventHandler(async (ev) => {

@ -1,6 +1,5 @@
import { listQuerier } from "@server/dbHelpers"; import { listQuerier } from "@server/dbHelpers";
import { Band } from "@models/band"; import { Band } from "@models/band";
import { Story } from "@models/stories";
export default eventHandler(async (event) => { export default eventHandler(async (event) => {
const params = getRouterParams(event); const params = getRouterParams(event);

@ -1,4 +1,3 @@
import { usernameRegex } from "@server/constants";
import { User } from "@models/user"; import { User } from "@models/user";
export default eventHandler(async (event) => { export default eventHandler(async (event) => {

@ -1,7 +1,6 @@
import san from "sanitize-html"; import san from "sanitize-html";
import { storyQuerier } from "@server/dbHelpers"; import { storyQuerier } from "@server/dbHelpers";
import { isLoggedIn } from "@server/middlewareButNotReally"; import { isLoggedIn } from "@server/middlewareButNotReally";
import { Story } from "@models/stories";
import { Review } from "@models/stories/review"; import { Review } from "@models/stories/review";
export default eventHandler(async (ev) => { export default eventHandler(async (ev) => {

@ -1,16 +1,10 @@
import { Readable } from "stream";
import { Document } from "mongoose"; import { Document } from "mongoose";
import { IStory, Story } from "@models/stories"; import { IStory, Story } from "@models/stories";
import { FormStory } from "@client/types/form/story"; import { FormStory } from "@client/types/form/story";
import { storyQuerier } from "@server/dbHelpers"; import { storyQuerier } from "@server/dbHelpers";
import { isLoggedIn } from "@server/middlewareButNotReally"; import { isLoggedIn } from "@server/middlewareButNotReally";
import { canModify } from "@server/middlewareButNotReally/storyPrivileges"; import { canModify } from "@server/middlewareButNotReally/storyPrivileges";
import { import { bodyHandler, getBucket, modelFormChapter, replaceOrUploadContent } from "@server/storyHelpers";
bodyHandler,
getBucket,
modelFormChapter,
replaceOrUploadContent,
} from "@server/storyHelpers";
import { countWords } from "@functions"; import { countWords } from "@functions";
import { messages } from "@server/constants"; import { messages } from "@server/constants";

@ -1,10 +1,8 @@
import { Readable } from "stream"; import { Readable } from "stream";
import san from "sanitize-html";
import { FormStory } from "@client/types/form/story"; import { FormStory } from "@client/types/form/story";
import { isLoggedIn } from "@server/middlewareButNotReally"; import { isLoggedIn } from "@server/middlewareButNotReally";
import { getBucket, bodyHandler, modelFormChapter } from "@server/storyHelpers"; import { getBucket, bodyHandler, modelFormChapter } from "@server/storyHelpers";
import { Story } from "@models/stories"; import { Story } from "@models/stories";
import { sanitizeConf } from "@server/constants";
import { countWords } from "@functions"; import { countWords } from "@functions";
export default eventHandler(async (ev) => { export default eventHandler(async (ev) => {
@ -24,9 +22,7 @@ export default eventHandler(async (ev) => {
}); });
for (const c of body.chapters) { for (const c of body.chapters) {
story.chapters.push(modelFormChapter(c)); story.chapters.push(modelFormChapter(c));
story.chapters[story.chapters.length - 1].words = countWords( story.chapters[story.chapters.length - 1].words = countWords(await bodyHandler(c));
await bodyHandler(c),
);
} }
await story.save(); await story.save();

@ -1,4 +1,4 @@
import { FavPayload, SubPayload } from "@client/types/form/favSub"; import { FavPayload } from "@client/types/form/favSub";
import { isLoggedIn } from "@server/middlewareButNotReally"; import { isLoggedIn } from "@server/middlewareButNotReally";
import { User } from "@models/user"; import { User } from "@models/user";

@ -1,7 +1,6 @@
import san from "sanitize-html";
import { weirdToNormalChars } from "weird-to-normal-chars"; import { weirdToNormalChars } from "weird-to-normal-chars";
import { Profile, MyStuff } from "@client/types/form/myStuff"; import { MyStuff } from "@client/types/form/myStuff";
import { apiRoot, messages } from "@server/constants"; import { apiRoot } from "@server/constants";
import { isLoggedIn } from "@server/middlewareButNotReally"; import { isLoggedIn } from "@server/middlewareButNotReally";
import { Review } from "@models/stories/review"; import { Review } from "@models/stories/review";
import { IUser, User } from "@models/user"; import { IUser, User } from "@models/user";
@ -51,14 +50,11 @@ export default eventHandler(async (ev) => {
if (exists) { if (exists) {
throw createError(emsg("username")); throw createError(emsg("username"));
} }
let { data: lookup } = await axios.get( let { data: lookup } = await axios.get(`${apiRoot}/session-sharing/lookup`, {
`${apiRoot}/session-sharing/lookup`, params: {
{ id: ev.context.currentUser!._id,
params: {
id: ev.context.currentUser!._id,
},
}, },
); });
await axios.put(`${apiRoot}/v3/users/${lookup.value.uid}`, { await axios.put(`${apiRoot}/v3/users/${lookup.value.uid}`, {
body: { body: {

@ -1,4 +1,3 @@
import mongoose from "mongoose";
import { log } from "@server/logger"; import { log } from "@server/logger";
import plugnplay from "@server/plugnplay"; import plugnplay from "@server/plugnplay";

@ -1,23 +1,26 @@
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import { log } from "@server/logger";
import { User } from "@models/user"; import { User } from "@models/user";
import { messages } from "@server/constants";
import { AccessToken } from "@models/oauth";
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
let ahead = ( let ahead = (getHeaders(event).authorization || getCookie(event, "auth:token") || "")?.replace("Bearer ", "");
getHeaders(event).authorization ||
getCookie(event, "auth:token") ||
""
)?.replace("Bearer ", "");
// console.log("in here fucknuts", ahead);
// log.debug(`'${ahead}'`, { label: "idk" });
if (ahead) { if (ahead) {
let toktok = jwt.verify( let toktok: jwt.JwtPayload;
ahead, try {
// ahead.replace("Bearer ", ""), toktok = jwt.verify(ahead, useRuntimeConfig().jwt) as jwt.JwtPayload;
useRuntimeConfig().jwt, let user = await User.findById(toktok.id as number).exec();
) as jwt.JwtPayload; if (user && toktok) event.context.currentUser = user;
let user = await User.findById(toktok.id as number).exec(); } catch (e) {
if (user && toktok) event.context.currentUser = user; const t = await AccessToken.findOne({ token: ahead });
// setCookie(event, "auth:token", ahead) if (!t)
throw createError({
statusCode: 401,
message: messages[401],
});
let user = await User.findById(t.userID);
if (user) event.context.currentUser = user;
// else throw createError({statusCode: 401, message: messages[401]})
}
} }
}); });

@ -1,4 +1,3 @@
import { Document } from "mongoose";
import { IStory } from "@models/stories"; import { IStory } from "@models/stories";
import { IUser } from "@models/user"; import { IUser } from "@models/user";
import { Request } from "express"; import { Request } from "express";

1
typings/h3.d.ts vendored

@ -1,4 +1,3 @@
import type { H3Event, H3EventContext } from "h3";
import { IFicmas } from "@models/challenges/ficmas"; import { IFicmas } from "@models/challenges/ficmas";
import { IUser } from "@models/user"; import { IUser } from "@models/user";
declare module "h3" { declare module "h3" {