rewrite settings + banners

This commit is contained in:
Emily
2024-10-04 14:39:08 +02:00
parent e1953f2f9f
commit c2846ca595
12 changed files with 129 additions and 268 deletions

3
TODO
View File

@@ -2,3 +2,6 @@
- Slice change on Actionable Chart - Slice change on Actionable Chart
- Show more on Dashboard cards - Show more on Dashboard cards
- Fix devices Dashboard card, replace empty with "unkwnwn"
- Component first interaction must make the request inside
- Reactivity on project delete

View File

@@ -24,8 +24,8 @@ function showMore() {
<template> <template>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<BarCardBase @showMore="showMore()" @dataReload="devicesData.refresh()" :data="devicesData.data.value || []" :dataIcons="false" <BarCardBase @showMore="showMore()" @dataReload="devicesData.refresh()" :data="devicesData.data.value || []"
desc="The devices most used to access your website." :loading="devicesData.pending.value" label="Top Devices" :dataIcons="false" desc="The devices most used to access your website." :loading="devicesData.pending.value"
sub-label="Devices"></BarCardBase> label="Top Devices" sub-label="Devices"></BarCardBase>
</div> </div>
</template> </template>

View File

@@ -0,0 +1,33 @@
<script lang="ts" setup>
const limitsInfo = await useFetch("/api/project/limits_info", {
lazy: true, headers: useComputedHeaders({ useSnapshotDates: false })
});
const pricingDrawer = usePricingDrawer();
function goToUpgrade() {
pricingDrawer.visible.value = true;
}
</script>
<template>
<div v-if="limitsInfo.data.value && limitsInfo.data.value.limited"
class="w-full bg-[#fbbf2422] p-4 rounded-lg text-[.9rem] flex items-center">
<div class="flex flex-col grow">
<div class="poppins font-semibold text-[#fbbf24]">
Limit reached
</div>
<div class="poppins text-[#fbbf24]">
Litlyx cannot receive new data as you reached your plan's limit. Resume all the great
features and collect even more data with a higher plan.
</div>
</div>
<div>
<LyxUiButton type="outline" @click="goToUpgrade()"> Upgrade </LyxUiButton>
</div>
</div>
</template>

View File

@@ -0,0 +1,37 @@
<script lang="ts" setup>
const pricingDrawer = usePricingDrawer();
function goToUpgrade() {
pricingDrawer.visible.value = true;
}
const { project } = useProject()
const isPremium = computed(() => {
return project.value?.premium ?? false;
});
</script>
<template>
<div v-if="!isPremium" class="w-full bg-[#5680f822] p-4 rounded-lg text-[.9rem] flex items-center">
<div class="flex flex-col grow">
<div class="poppins font-semibold text-lyx-primary">
Launch offer: 25% off
</div>
<div class="poppins text-lyx-primary">
We're offering an exclusive 25% discount forever on all plans starting from the Acceleration
Plan for our first 100 users who believe in our project.
<br>
Redeem Code: <span class="text-white font-bold text-[1rem]">LIT25</span> at checkout to
claim your discount.
</div>
</div>
<div>
<LyxUiButton type="outline" @click="goToUpgrade()"> Upgrade </LyxUiButton>
</div>
</div>
</template>

View File

@@ -2,6 +2,7 @@
import type { TApiSettings } from '@schema/ApiSettingsSchema'; import type { TApiSettings } from '@schema/ApiSettingsSchema';
import type { SettingsTemplateEntry } from './Template.vue'; import type { SettingsTemplateEntry } from './Template.vue';
const { project } = useProject();
const entries: SettingsTemplateEntry[] = [ const entries: SettingsTemplateEntry[] = [
{ id: 'pname', title: 'Name', text: 'Project name' }, { id: 'pname', title: 'Name', text: 'Project name' },
@@ -11,8 +12,7 @@ const entries: SettingsTemplateEntry[] = [
{ id: 'pdelete', title: 'Delete', text: 'Delete current project' }, { id: 'pdelete', title: 'Delete', text: 'Delete current project' },
] ]
const activeProject = useActiveProject(); const projectNameInputVal = ref<string>(project.value?.name || '');
const projectNameInputVal = ref<string>(activeProject.value?.name || '');
const apiKeys = ref<TApiSettings[]>([]); const apiKeys = ref<TApiSettings[]>([]);
@@ -20,14 +20,17 @@ const newApiKeyName = ref<string>('');
async function updateApiKeys() { async function updateApiKeys() {
newApiKeyName.value = ''; newApiKeyName.value = '';
apiKeys.value = await $fetch<TApiSettings[]>('/api/keys/get_all', signHeaders()); apiKeys.value = await $fetch<TApiSettings[]>('/api/keys/get_all', signHeaders({
'x-pid': project.value?._id.toString() ?? ''
}));
} }
async function createApiKey() { async function createApiKey() {
try { try {
const res = await $fetch<TApiSettings>('/api/keys/create', { const res = await $fetch<TApiSettings>('/api/keys/create', {
method: 'POST', ...signHeaders({ method: 'POST', ...signHeaders({
'Content-Type': 'application/json' 'Content-Type': 'application/json',
'x-pid': project.value?._id.toString() ?? ''
}), }),
body: JSON.stringify({ name: newApiKeyName.value }) body: JSON.stringify({ name: newApiKeyName.value })
}); });
@@ -42,7 +45,8 @@ async function deleteApiKey(api_id: string) {
try { try {
const res = await $fetch<TApiSettings>('/api/keys/delete', { const res = await $fetch<TApiSettings>('/api/keys/delete', {
method: 'DELETE', ...signHeaders({ method: 'DELETE', ...signHeaders({
'Content-Type': 'application/json' 'Content-Type': 'application/json',
'x-pid': project.value?._id.toString() ?? ''
}), }),
body: JSON.stringify({ api_id }) body: JSON.stringify({ api_id })
}); });
@@ -56,15 +60,15 @@ async function deleteApiKey(api_id: string) {
onMounted(() => { onMounted(() => {
updateApiKeys(); updateApiKeys();
}) });
watch(activeProject, () => { watch(project, () => {
projectNameInputVal.value = activeProject.value?.name || ""; projectNameInputVal.value = project.value?.name || "";
updateApiKeys(); updateApiKeys();
}) });
const canChange = computed(() => { const canChange = computed(() => {
if (activeProject.value?.name == projectNameInputVal.value) return false; if (project.value?.name == projectNameInputVal.value) return false;
if (projectNameInputVal.value.length === 0) return false; if (projectNameInputVal.value.length === 0) return false;
return true; return true;
}); });
@@ -80,8 +84,8 @@ async function changeProjectName() {
} }
async function deleteProject() { async function deleteProject() {
if (!activeProject.value) return; if (!project.value) return;
const sure = confirm(`Are you sure to delete the project ${activeProject.value.name} ?`); const sure = confirm(`Are you sure to delete the project ${project.value.name} ?`);
if (!sure) return; if (!sure) return;
try { try {
@@ -89,7 +93,7 @@ async function deleteProject() {
await $fetch('/api/project/delete', { await $fetch('/api/project/delete', {
method: 'DELETE', method: 'DELETE',
...signHeaders({ 'Content-Type': 'application/json' }), ...signHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify({ project_id: activeProject.value._id.toString() }) body: JSON.stringify({ project_id: project.value._id.toString() })
}); });
const projectsList = useProjectsList() const projectsList = useProjectsList()
@@ -142,7 +146,7 @@ function copyProjectId() {
<template> <template>
<SettingsTemplate :entries="entries" :key="activeProject?.name || 'NONE'"> <SettingsTemplate :entries="entries" :key="project?.name || 'NONE'">
<template #pname> <template #pname>
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<LyxUiInput class="w-full px-4 py-2" v-model="projectNameInputVal"></LyxUiInput> <LyxUiInput class="w-full px-4 py-2" v-model="projectNameInputVal"></LyxUiInput>
@@ -174,7 +178,7 @@ function copyProjectId() {
</template> </template>
<template #pid> <template #pid>
<LyxUiCard class="w-full flex items-center"> <LyxUiCard class="w-full flex items-center">
<div class="grow">{{ activeProject?._id.toString() }}</div> <div class="grow">{{ project?._id.toString() }}</div>
<div><i class="far fa-copy" @click="copyProjectId()"></i></div> <div><i class="far fa-copy" @click="copyProjectId()"></i></div>
</LyxUiCard> </LyxUiCard>
</template> </template>
@@ -182,7 +186,7 @@ function copyProjectId() {
<LyxUiCard class="w-full flex items-center"> <LyxUiCard class="w-full flex items-center">
<div class="grow"> <div class="grow">
{{ ` {{ `
<script defer data-project="${activeProject?._id}" <script defer data-project="${project?._id}"
src="https://cdn.jsdelivr.net/gh/litlyx/litlyx-js/browser/litlyx.js"></script>` }} src="https://cdn.jsdelivr.net/gh/litlyx/litlyx-js/browser/litlyx.js"></script>` }}
</div> </div>
<div><i class="far fa-copy" @click="copyScript()"></i></div> <div><i class="far fa-copy" @click="copyScript()"></i></div>

View File

@@ -15,7 +15,6 @@ const { projectId } = useProject();
const { safeSnapshotDates } = useSnapshot() const { safeSnapshotDates } = useSnapshot()
function getValueFromRefOrPrimitive<T>(data?: T | Ref<T> | ComputedRef<T>) { function getValueFromRefOrPrimitive<T>(data?: T | Ref<T> | ComputedRef<T>) {
console.log('Getting value of', data);
if (!data) return; if (!data) return;
if (isRef(data)) return data.value; if (isRef(data)) return data.value;
return data; return data;
@@ -30,7 +29,6 @@ export function useComputedHeaders(customOptions?: CustomOptions) {
const parsedCustom: Record<string, string> = {} const parsedCustom: Record<string, string> = {}
const customKeys = Object.keys(customOptions?.custom || {}); const customKeys = Object.keys(customOptions?.custom || {});
for (const key of customKeys) { for (const key of customKeys) {
console.log('key', key);
parsedCustom[key] = getValueFromRefOrPrimitive((customOptions?.custom || {})[key]) ?? '' parsedCustom[key] = getValueFromRefOrPrimitive((customOptions?.custom || {})[key]) ?? ''
} }

View File

@@ -3,68 +3,16 @@
definePageMeta({ layout: 'dashboard' }); definePageMeta({ layout: 'dashboard' });
const { project } = useProject();
const { data: projects } = useProjectsList();
const activeProject = useActiveProject();
const mainChartSelectIndex = ref<number>(1);
const sessionsChartSelectIndex = ref<number>(1);
const route = useRoute(); const route = useRoute();
const { project, projectList } = useProject();
const justLogged = computed(() => route.query.just_logged);
const limitsInfo = ref<{
limited: boolean,
maxLimit: number,
limit: number,
total: number,
percent: number
}>();
const justLogged = computed(() => {
return route.query.just_logged;
})
onMounted(async () => {
if (route.query.just_logged) return location.href = '/';
limitsInfo.value = await $fetch<any>("/api/project/limits_info", signHeaders());
watch(activeProject, async () => {
limitsInfo.value = await $fetch<any>("/api/project/limits_info", signHeaders());
});
});
const firstInteraction = useFetch<boolean>('/api/project/first_interaction', { const firstInteraction = useFetch<boolean>('/api/project/first_interaction', {
lazy: true, headers: useComputedHeaders({ useSnapshotDates: false }) lazy: true, headers: useComputedHeaders({ useSnapshotDates: false })
}); });
const showDashboard = computed(() => project.value && firstInteraction.data.value);
const showDashboard = computed(() => {
return project.value && firstInteraction.data.value
});
const selectLabels = [
{ label: 'Hour', value: 'hour' },
{ label: 'Day', value: 'day' },
// { label: 'Month', value: 'month' },
];
const { snapshot } = useSnapshot();
const isPremium = computed(() => {
return activeProject.value?.premium;
})
const pricingDrawer = usePricingDrawer();
function goToUpgrade() {
pricingDrawer.visible.value = true;
}
</script> </script>
@@ -75,40 +23,8 @@ function goToUpgrade() {
<div v-if="showDashboard"> <div v-if="showDashboard">
<div class="w-full px-4 py-2 gap-2 flex flex-col"> <div class="w-full px-4 py-2 gap-2 flex flex-col">
<BannerLimitsInfo :key="refreshKey"></BannerLimitsInfo>
<!-- <div v-if="limitsInfo && limitsInfo.limited" <BannerOffer :key="refreshKey"></BannerOffer>
class="w-full bg-[#fbbf2422] p-4 rounded-lg text-[.9rem] flex items-center">
<div class="flex flex-col grow">
<div class="poppins font-semibold text-[#fbbf24]">
Limit reached
</div>
<div class="poppins text-[#fbbf24]">
Litlyx cannot receive new data as you reached your plan's limit. Resume all the great
features and collect even more data with a higher plan.
</div>
</div>
<div>
<LyxUiButton type="outline" @click="goToUpgrade()"> Upgrade </LyxUiButton>
</div>
</div> -->
<!-- <div v-if="!isPremium" class="w-full bg-[#5680f822] p-4 rounded-lg text-[.9rem] flex items-center">
<div class="flex flex-col grow">
<div class="poppins font-semibold text-lyx-primary">
Launch offer: 25% off
</div>
<div class="poppins text-lyx-primary">
We're offering an exclusive 25% discount forever on all plans starting from the Acceleration
Plan for our first 100 users who believe in our project.
<br>
Redeem Code: <span class="text-white font-bold text-[1rem]">LIT25</span> at checkout to
claim your discount.
</div>
</div>
<div>
<LyxUiButton type="outline" @click="goToUpgrade()"> Upgrade </LyxUiButton>
</div>
</div> -->
</div> </div>
<div> <div>
@@ -165,108 +81,17 @@ function goToUpgrade() {
</div> </div>
<!-- <div :key="'home-' + isLiveDemo()"
v-if="projects && activeProject && (firstInteraction.data.value === true) && !justLogged">
<div class="w-full px-4 py-2 gap-2 flex flex-col">
<div v-if="limitsInfo && limitsInfo.limited"
class="w-full bg-[#fbbf2422] p-4 rounded-lg text-[.9rem] flex items-center">
<div class="flex flex-col grow">
<div class="poppins font-semibold text-[#fbbf24]">
Limit reached
</div>
<div class="poppins text-[#fbbf24]">
Litlyx cannot receive new data as you reached your plan's limit. Resume all the great
features and collect even more data with a higher plan.
</div>
</div>
<div>
<LyxUiButton type="outline" @click="goToUpgrade()"> Upgrade </LyxUiButton>
</div>
</div>
<div v-if="!isPremium" class="w-full bg-[#5680f822] p-4 rounded-lg text-[.9rem] flex items-center">
<div class="flex flex-col grow">
<div class="poppins font-semibold text-lyx-primary">
Launch offer: 25% off
</div>
<div class="poppins text-lyx-primary">
We're offering an exclusive 25% discount forever on all plans starting from the Acceleration
Plan for our first 100 users who believe in our project.
<br>
Redeem Code: <span class="text-white font-bold text-[1rem]">LIT25</span> at checkout to
claim your discount.
</div>
</div>
<div>
<LyxUiButton type="outline" @click="goToUpgrade()"> Upgrade </LyxUiButton>
</div>
</div>
</div>
<DashboardTopSection :key="refreshKey"></DashboardTopSection>
<DashboardTopCards :key="refreshKey"></DashboardTopCards>
<div class="mt-6 px-6 flex gap-6 flex-col 2xl:flex-row w-full">
<DashboardActionableChart :key="refreshKey"></DashboardActionableChart>
</div>
<div class="flex w-full justify-center mt-6 px-6">
<div class="flex w-full gap-6 flex-col xl:flex-row">
<div class="flex-1">
<DashboardWebsitesBarCard :key="refreshKey"></DashboardWebsitesBarCard>
</div>
<div class="flex-1">
<DashboardEventsBarCard :key="refreshKey"></DashboardEventsBarCard>
</div>
</div>
</div>
<div class="flex w-full justify-center mt-6 px-6">
<div class="flex w-full gap-6 flex-col xl:flex-row">
<div class="flex-1">
<DashboardReferrersBarCard :key="refreshKey"></DashboardReferrersBarCard>
</div>
<div class="flex-1">
<DashboardBrowsersBarCard :key="refreshKey"></DashboardBrowsersBarCard>
</div>
</div>
</div>
<div class="flex w-full justify-center mt-6 px-6">
<div class="flex w-full gap-6 flex-col xl:flex-row">
<div class="flex-1">
<DashboardOssBarCard :key="refreshKey"></DashboardOssBarCard>
</div>
<div class="flex-1">
<DashboardGeolocationBarCard :key="refreshKey"></DashboardGeolocationBarCard>
</div>
</div>
</div>
<div class="flex w-full justify-center mt-6 px-6">
<div class="flex w-full gap-6 flex-col xl:flex-row">
<div class="flex-1">
<DashboardDevicesBarCard :key="refreshKey"></DashboardDevicesBarCard>
</div>
<div class="flex-1">
</div>
</div>
</div>
</div>
<FirstInteraction v-if="!justLogged" :refresh-interaction="firstInteraction.refresh" <FirstInteraction v-if="!justLogged" :refresh-interaction="firstInteraction.refresh"
:first-interaction="(firstInteraction.data.value || false)"></FirstInteraction> :first-interaction="(firstInteraction.data.value || false)"></FirstInteraction>
<div class="text-text/85 mt-8 ml-8 poppis text-[1.2rem]" v-if="projects && projects.length == 0 && !justLogged"> <div class="text-text/85 mt-8 ml-8 poppis text-[1.2rem]" v-if="projectList && projectList.length == 0 && !justLogged">
Create your first project... Create your first project...
</div> </div>
<div v-if="justLogged" class="text-[2rem]"> <div v-if="justLogged" class="text-[2rem]">
The page will refresh soon The page will refresh soon
</div> --> </div>
</div> </div>

View File

@@ -19,20 +19,10 @@ export default defineEventHandler(async event => {
if (body.name.length < 3) return setResponseStatus(event, 400, 'name too short'); if (body.name.length < 3) return setResponseStatus(event, 400, 'name too short');
if (body.name.length > 32) return setResponseStatus(event, 400, 'name too long'); if (body.name.length > 32) return setResponseStatus(event, 400, 'name too long');
const userData = getRequestUser(event); const data = await getRequestData(event, { allowGuests: false, allowLitlyx: false, });
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged'); if (!data) return;
const currentActiveProject = await UserSettingsModel.findOne({ user_id: userData.id }); const { project_id } = data;
if (!currentActiveProject) return setResponseStatus(event, 400, 'You need to select a project');
const project_id = currentActiveProject.active_project_id;
const project = await ProjectModel.findById(project_id);
if (!project) return setResponseStatus(event, 400, 'Project not found');
if (project.owner.toString() != userData.id) {
return setResponseStatus(event, 400, 'You are not the owner');
}
const key = generateApiKey(); const key = generateApiKey();

View File

@@ -1,28 +1,16 @@
import { ApiSettingsModel } from "@schema/ApiSettingsSchema"; import { ApiSettingsModel } from "@schema/ApiSettingsSchema";
import { UserSettingsModel } from "@schema/UserSettings";
import { ProjectModel } from "@schema/ProjectSchema";
export default defineEventHandler(async event => { export default defineEventHandler(async event => {
const body = await readBody(event); const body = await readBody(event);
const userData = getRequestUser(event); const data = await getRequestData(event, { allowGuests: false, allowLitlyx: false, });
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged'); if (!data) return;
const currentActiveProject = await UserSettingsModel.findOne({ user_id: userData.id }); const { project_id } = data;
if (!currentActiveProject) return setResponseStatus(event, 400, 'You need to select a project');
const project_id = currentActiveProject.active_project_id; const deletation = await ApiSettingsModel.deleteOne({ project_id, _id: body.api_id });
const project = await ProjectModel.findById(project_id);
if (!project) return setResponseStatus(event, 400, 'Project not found');
if (project.owner.toString() != userData.id) {
return setResponseStatus(event, 400, 'You are not the owner');
}
const deletation = await ApiSettingsModel.deleteOne({ _id: body.api_id });
return { ok: deletation.acknowledged }; return { ok: deletation.acknowledged };
}); });

View File

@@ -1,9 +1,5 @@
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
import { ApiSettingsModel, TApiSettings } from "@schema/ApiSettingsSchema"; import { ApiSettingsModel, TApiSettings } from "@schema/ApiSettingsSchema";
import { UserSettingsModel } from "@schema/UserSettings";
import { ProjectModel } from "@schema/ProjectSchema";
function cryptApiKeyName(apiSettings: TApiSettings): TApiSettings { function cryptApiKeyName(apiSettings: TApiSettings): TApiSettings {
return { ...apiSettings, apiKey: apiSettings.apiKey.substring(0, 6) + '******' } return { ...apiSettings, apiKey: apiSettings.apiKey.substring(0, 6) + '******' }
@@ -11,23 +7,12 @@ function cryptApiKeyName(apiSettings: TApiSettings): TApiSettings {
export default defineEventHandler(async event => { export default defineEventHandler(async event => {
const userData = getRequestUser(event); const data = await getRequestData(event, { allowGuests: false, allowLitlyx: false, requireRange: false });
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged'); if (!data) return;
const currentActiveProject = await UserSettingsModel.findOne({ user_id: userData.id }); const { project_id } = data;
if (!currentActiveProject) return setResponseStatus(event, 400, 'You need to select a project');
const project_id = currentActiveProject.active_project_id;
const project = await ProjectModel.findById(project_id);
if (!project) return setResponseStatus(event, 400, 'Project not found');
if (project.owner.toString() != userData.id) {
return setResponseStatus(event, 400, 'You are not the owner');
}
const apiKeys = await ApiSettingsModel.find({ project_id }, { project_id: 0 }) const apiKeys = await ApiSettingsModel.find({ project_id }, { project_id: 0 })
return apiKeys.map(e => cryptApiKeyName(e.toJSON())) as TApiSettings[]; return apiKeys.map(e => cryptApiKeyName(e.toJSON())) as TApiSettings[];
}); });

View File

@@ -1,20 +1,15 @@
import { ProjectModel, TProject } from "@schema/ProjectSchema";
import { ProjectLimitModel } from "@schema/ProjectsLimits"; import { ProjectLimitModel } from "@schema/ProjectsLimits";
import { UserSettingsModel } from "@schema/UserSettings";
import { MAX_LOG_LIMIT_PERCENT } from '@data/broker/Limits'; import { MAX_LOG_LIMIT_PERCENT } from '@data/broker/Limits';
export default defineEventHandler(async event => { export default defineEventHandler(async event => {
const userData = getRequestUser(event);
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged');
const currentActiveProject = await UserSettingsModel.findOne({ user_id: userData.id });
if (!currentActiveProject) return setResponseStatus(event, 400, 'You need to select a project');
const project_id = currentActiveProject.active_project_id; const data = await getRequestData(event);
if (!data) return;
const project = await ProjectModel.findById(project_id); const { project_id } = data;
if (!project) return setResponseStatus(event, 400, 'Project not found');
const projectLimits = await ProjectLimitModel.findOne({ project_id }); const projectLimits = await ProjectLimitModel.findOne({ project_id });
if (!projectLimits) return; if (!projectLimits) return;

View File

@@ -23,12 +23,12 @@ export function getRequestAddress(event: H3Event<EventHandlerRequest>) {
} }
export type GetRequestDataOptions = { export type GetRequestDataOptions = {
allowGuests?: boolean, /** @default true */ allowGuests?: boolean,
requireSchema?: boolean, /** @default false */ requireSchema?: boolean,
allowLitlyx?: boolean, /** @default true */ allowLitlyx?: boolean,
requireSlice?: boolean /** @default false */ requireSlice?: boolean,
/** @default true */ requireRange?: boolean,
} }
async function hasAccessToProject(user_id: string, project: TProject) { async function hasAccessToProject(user_id: string, project: TProject) {
@@ -48,6 +48,7 @@ export async function getRequestData(event: H3Event<EventHandlerRequest>, option
const allowGuests = options?.allowGuests || true; const allowGuests = options?.allowGuests || true;
const allowLitlyx = options?.allowLitlyx || true; const allowLitlyx = options?.allowLitlyx || true;
const requireSlice = options?.requireSlice || false; const requireSlice = options?.requireSlice || false;
const requireRange = options?.requireRange || false;
const pid = getHeader(event, 'x-pid'); const pid = getHeader(event, 'x-pid');
if (!pid) return setResponseStatus(event, 400, 'x-pid is required'); if (!pid) return setResponseStatus(event, 400, 'x-pid is required');
@@ -57,7 +58,9 @@ export async function getRequestData(event: H3Event<EventHandlerRequest>, option
const from = getRequestHeader(event, 'x-from'); const from = getRequestHeader(event, 'x-from');
const to = getRequestHeader(event, 'x-to'); const to = getRequestHeader(event, 'x-to');
if (requireRange) {
if (!from || !to) return setResponseStatus(event, 400, 'x-from and x-to are required'); if (!from || !to) return setResponseStatus(event, 400, 'x-from and x-to are required');
}
let model: Model<any> = undefined as any; let model: Model<any> = undefined as any;