mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-09 23:48:36 +01:00
rewrite settings + banners
This commit is contained in:
5
TODO
5
TODO
@@ -1,4 +1,7 @@
|
||||
|
||||
|
||||
- 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
|
||||
@@ -24,8 +24,8 @@ function showMore() {
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<BarCardBase @showMore="showMore()" @dataReload="devicesData.refresh()" :data="devicesData.data.value || []" :dataIcons="false"
|
||||
desc="The devices most used to access your website." :loading="devicesData.pending.value" label="Top Devices"
|
||||
sub-label="Devices"></BarCardBase>
|
||||
<BarCardBase @showMore="showMore()" @dataReload="devicesData.refresh()" :data="devicesData.data.value || []"
|
||||
:dataIcons="false" desc="The devices most used to access your website." :loading="devicesData.pending.value"
|
||||
label="Top Devices" sub-label="Devices"></BarCardBase>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
33
dashboard/components/banner/LimitsInfo.vue
Normal file
33
dashboard/components/banner/LimitsInfo.vue
Normal 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>
|
||||
37
dashboard/components/banner/Offer.vue
Normal file
37
dashboard/components/banner/Offer.vue
Normal 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>
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { TApiSettings } from '@schema/ApiSettingsSchema';
|
||||
import type { SettingsTemplateEntry } from './Template.vue';
|
||||
|
||||
const { project } = useProject();
|
||||
|
||||
const entries: SettingsTemplateEntry[] = [
|
||||
{ id: 'pname', title: 'Name', text: 'Project name' },
|
||||
@@ -11,8 +12,7 @@ const entries: SettingsTemplateEntry[] = [
|
||||
{ id: 'pdelete', title: 'Delete', text: 'Delete current project' },
|
||||
]
|
||||
|
||||
const activeProject = useActiveProject();
|
||||
const projectNameInputVal = ref<string>(activeProject.value?.name || '');
|
||||
const projectNameInputVal = ref<string>(project.value?.name || '');
|
||||
|
||||
const apiKeys = ref<TApiSettings[]>([]);
|
||||
|
||||
@@ -20,14 +20,17 @@ const newApiKeyName = ref<string>('');
|
||||
|
||||
async function updateApiKeys() {
|
||||
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() {
|
||||
try {
|
||||
const res = await $fetch<TApiSettings>('/api/keys/create', {
|
||||
method: 'POST', ...signHeaders({
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'x-pid': project.value?._id.toString() ?? ''
|
||||
}),
|
||||
body: JSON.stringify({ name: newApiKeyName.value })
|
||||
});
|
||||
@@ -42,7 +45,8 @@ async function deleteApiKey(api_id: string) {
|
||||
try {
|
||||
const res = await $fetch<TApiSettings>('/api/keys/delete', {
|
||||
method: 'DELETE', ...signHeaders({
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
'x-pid': project.value?._id.toString() ?? ''
|
||||
}),
|
||||
body: JSON.stringify({ api_id })
|
||||
});
|
||||
@@ -56,15 +60,15 @@ async function deleteApiKey(api_id: string) {
|
||||
|
||||
onMounted(() => {
|
||||
updateApiKeys();
|
||||
})
|
||||
});
|
||||
|
||||
watch(activeProject, () => {
|
||||
projectNameInputVal.value = activeProject.value?.name || "";
|
||||
watch(project, () => {
|
||||
projectNameInputVal.value = project.value?.name || "";
|
||||
updateApiKeys();
|
||||
})
|
||||
});
|
||||
|
||||
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;
|
||||
return true;
|
||||
});
|
||||
@@ -80,8 +84,8 @@ async function changeProjectName() {
|
||||
}
|
||||
|
||||
async function deleteProject() {
|
||||
if (!activeProject.value) return;
|
||||
const sure = confirm(`Are you sure to delete the project ${activeProject.value.name} ?`);
|
||||
if (!project.value) return;
|
||||
const sure = confirm(`Are you sure to delete the project ${project.value.name} ?`);
|
||||
if (!sure) return;
|
||||
|
||||
try {
|
||||
@@ -89,7 +93,7 @@ async function deleteProject() {
|
||||
await $fetch('/api/project/delete', {
|
||||
method: 'DELETE',
|
||||
...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()
|
||||
@@ -142,7 +146,7 @@ function copyProjectId() {
|
||||
|
||||
|
||||
<template>
|
||||
<SettingsTemplate :entries="entries" :key="activeProject?.name || 'NONE'">
|
||||
<SettingsTemplate :entries="entries" :key="project?.name || 'NONE'">
|
||||
<template #pname>
|
||||
<div class="flex items-center gap-4">
|
||||
<LyxUiInput class="w-full px-4 py-2" v-model="projectNameInputVal"></LyxUiInput>
|
||||
@@ -174,7 +178,7 @@ function copyProjectId() {
|
||||
</template>
|
||||
<template #pid>
|
||||
<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>
|
||||
</LyxUiCard>
|
||||
</template>
|
||||
@@ -182,7 +186,7 @@ function copyProjectId() {
|
||||
<LyxUiCard class="w-full flex items-center">
|
||||
<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>` }}
|
||||
</div>
|
||||
<div><i class="far fa-copy" @click="copyScript()"></i></div>
|
||||
|
||||
@@ -15,7 +15,6 @@ const { projectId } = useProject();
|
||||
const { safeSnapshotDates } = useSnapshot()
|
||||
|
||||
function getValueFromRefOrPrimitive<T>(data?: T | Ref<T> | ComputedRef<T>) {
|
||||
console.log('Getting value of', data);
|
||||
if (!data) return;
|
||||
if (isRef(data)) return data.value;
|
||||
return data;
|
||||
@@ -30,7 +29,6 @@ export function useComputedHeaders(customOptions?: CustomOptions) {
|
||||
const parsedCustom: Record<string, string> = {}
|
||||
const customKeys = Object.keys(customOptions?.custom || {});
|
||||
for (const key of customKeys) {
|
||||
console.log('key', key);
|
||||
parsedCustom[key] = getValueFromRefOrPrimitive((customOptions?.custom || {})[key]) ?? ''
|
||||
}
|
||||
|
||||
|
||||
@@ -3,68 +3,16 @@
|
||||
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 { project, projectList } = useProject();
|
||||
|
||||
|
||||
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 justLogged = computed(() => route.query.just_logged);
|
||||
|
||||
const firstInteraction = useFetch<boolean>('/api/project/first_interaction', {
|
||||
lazy: true, headers: useComputedHeaders({ useSnapshotDates: false })
|
||||
});
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const showDashboard = computed(() => project.value && firstInteraction.data.value);
|
||||
|
||||
</script>
|
||||
|
||||
@@ -75,40 +23,8 @@ function goToUpgrade() {
|
||||
<div v-if="showDashboard">
|
||||
|
||||
<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> -->
|
||||
|
||||
<BannerLimitsInfo :key="refreshKey"></BannerLimitsInfo>
|
||||
<BannerOffer :key="refreshKey"></BannerOffer>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -148,7 +64,7 @@ function goToUpgrade() {
|
||||
<BarCardOperatingSystems :key="refreshKey"></BarCardOperatingSystems>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<BarCardGeolocations :key="refreshKey"></BarCardGeolocations>
|
||||
<BarCardGeolocations :key="refreshKey"></BarCardGeolocations>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -165,108 +81,17 @@ function goToUpgrade() {
|
||||
|
||||
</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"
|
||||
: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...
|
||||
</div>
|
||||
|
||||
<div v-if="justLogged" class="text-[2rem]">
|
||||
The page will refresh soon
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -19,21 +19,11 @@ export default defineEventHandler(async event => {
|
||||
if (body.name.length < 3) return setResponseStatus(event, 400, 'name too short');
|
||||
if (body.name.length > 32) return setResponseStatus(event, 400, 'name too long');
|
||||
|
||||
const userData = getRequestUser(event);
|
||||
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged');
|
||||
const data = await getRequestData(event, { allowGuests: false, allowLitlyx: false, });
|
||||
if (!data) return;
|
||||
|
||||
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 project = await ProjectModel.findById(project_id);
|
||||
if (!project) return setResponseStatus(event, 400, 'Project not found');
|
||||
const { project_id } = data;
|
||||
|
||||
if (project.owner.toString() != userData.id) {
|
||||
return setResponseStatus(event, 400, 'You are not the owner');
|
||||
}
|
||||
|
||||
const key = generateApiKey();
|
||||
|
||||
const keyNumbers = await ApiSettingsModel.countDocuments({ project_id });
|
||||
|
||||
@@ -1,28 +1,16 @@
|
||||
|
||||
import { ApiSettingsModel } from "@schema/ApiSettingsSchema";
|
||||
import { UserSettingsModel } from "@schema/UserSettings";
|
||||
import { ProjectModel } from "@schema/ProjectSchema";
|
||||
|
||||
export default defineEventHandler(async event => {
|
||||
|
||||
const body = await readBody(event);
|
||||
|
||||
const userData = getRequestUser(event);
|
||||
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged');
|
||||
const data = await getRequestData(event, { allowGuests: false, allowLitlyx: false, });
|
||||
if (!data) return;
|
||||
|
||||
const currentActiveProject = await UserSettingsModel.findOne({ user_id: userData.id });
|
||||
if (!currentActiveProject) return setResponseStatus(event, 400, 'You need to select a project');
|
||||
const { project_id } = data;
|
||||
|
||||
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 deletation = await ApiSettingsModel.deleteOne({ _id: body.api_id });
|
||||
const deletation = await ApiSettingsModel.deleteOne({ project_id, _id: body.api_id });
|
||||
return { ok: deletation.acknowledged };
|
||||
|
||||
});
|
||||
@@ -1,9 +1,5 @@
|
||||
|
||||
import { getUserProjectFromId } from "~/server/LIVE_DEMO_DATA";
|
||||
import { ApiSettingsModel, TApiSettings } from "@schema/ApiSettingsSchema";
|
||||
import { UserSettingsModel } from "@schema/UserSettings";
|
||||
import { ProjectModel } from "@schema/ProjectSchema";
|
||||
|
||||
|
||||
function cryptApiKeyName(apiSettings: TApiSettings): TApiSettings {
|
||||
return { ...apiSettings, apiKey: apiSettings.apiKey.substring(0, 6) + '******' }
|
||||
@@ -11,23 +7,12 @@ function cryptApiKeyName(apiSettings: TApiSettings): TApiSettings {
|
||||
|
||||
export default defineEventHandler(async event => {
|
||||
|
||||
const userData = getRequestUser(event);
|
||||
if (!userData?.logged) return setResponseStatus(event, 400, 'NotLogged');
|
||||
const data = await getRequestData(event, { allowGuests: false, allowLitlyx: false, requireRange: false });
|
||||
if (!data) return;
|
||||
|
||||
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 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 { project_id } = data;
|
||||
|
||||
const apiKeys = await ApiSettingsModel.find({ project_id }, { project_id: 0 })
|
||||
|
||||
return apiKeys.map(e => cryptApiKeyName(e.toJSON())) as TApiSettings[];
|
||||
|
||||
});
|
||||
@@ -1,27 +1,22 @@
|
||||
import { ProjectModel, TProject } from "@schema/ProjectSchema";
|
||||
|
||||
import { ProjectLimitModel } from "@schema/ProjectsLimits";
|
||||
import { UserSettingsModel } from "@schema/UserSettings";
|
||||
import { MAX_LOG_LIMIT_PERCENT } from '@data/broker/Limits';
|
||||
|
||||
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);
|
||||
if (!project) return setResponseStatus(event, 400, 'Project not found');
|
||||
const { project_id } = data;
|
||||
|
||||
const projectLimits = await ProjectLimitModel.findOne({ project_id });
|
||||
if (!projectLimits) return;
|
||||
|
||||
const TOTAL_COUNT = projectLimits.events + projectLimits.visits;
|
||||
const COUNT_LIMIT = projectLimits.limit;
|
||||
|
||||
|
||||
return {
|
||||
total: TOTAL_COUNT,
|
||||
limit: COUNT_LIMIT,
|
||||
|
||||
@@ -23,12 +23,12 @@ export function getRequestAddress(event: H3Event<EventHandlerRequest>) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
export type GetRequestDataOptions = {
|
||||
allowGuests?: boolean,
|
||||
requireSchema?: boolean,
|
||||
allowLitlyx?: boolean,
|
||||
requireSlice?: boolean
|
||||
/** @default true */ allowGuests?: boolean,
|
||||
/** @default false */ requireSchema?: boolean,
|
||||
/** @default true */ allowLitlyx?: boolean,
|
||||
/** @default false */ requireSlice?: boolean,
|
||||
/** @default true */ requireRange?: boolean,
|
||||
}
|
||||
|
||||
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 allowLitlyx = options?.allowLitlyx || true;
|
||||
const requireSlice = options?.requireSlice || false;
|
||||
const requireRange = options?.requireRange || false;
|
||||
|
||||
const pid = getHeader(event, 'x-pid');
|
||||
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 to = getRequestHeader(event, 'x-to');
|
||||
if (!from || !to) return setResponseStatus(event, 400, 'x-from and x-to are required');
|
||||
if (requireRange) {
|
||||
if (!from || !to) return setResponseStatus(event, 400, 'x-from and x-to are required');
|
||||
}
|
||||
|
||||
|
||||
let model: Model<any> = undefined as any;
|
||||
|
||||
Reference in New Issue
Block a user