makes profiles public

This commit is contained in:
Christian Beutel
2024-11-16 15:13:22 +01:00
parent 2e8d7f5e82
commit dcc8da83e7
19 changed files with 364 additions and 41 deletions

View File

@@ -0,0 +1,38 @@
package migrations
import (
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
m "github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/tools/types"
)
func init() {
m.Register(func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
if err != nil {
return err
}
collection.ListRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.summit_logs.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.summit_logs.id ?= id && @collection.trails.public ?= true) || (author = @request.auth.id)")
collection.ViewRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.summit_logs.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.summit_logs.id ?= id && @collection.trails.public ?= true) || (author = @request.auth.id)")
return dao.SaveCollection(collection)
}, func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
if err != nil {
return err
}
collection.ListRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.summit_logs.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.summit_logs.id ?= id && @collection.trails.public = true) || (author = @request.auth.id)")
collection.ViewRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.summit_logs.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.summit_logs.id ?= id && @collection.trails.public = true) || (author = @request.auth.id)")
return dao.SaveCollection(collection)
})
}

View File

@@ -0,0 +1,156 @@
package migrations
import (
"encoding/json"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
m "github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/models/schema"
)
func init() {
m.Register(func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("xku110v5a5xbufa")
if err != nil {
return err
}
options := map[string]any{}
if err := json.Unmarshal([]byte(`{
"query": "SELECT id, username, avatar, created FROM users"
}`), &options); err != nil {
return err
}
collection.SetOptions(options)
// remove
collection.Schema.RemoveField("ogrxf4ps")
// remove
collection.Schema.RemoveField("7k4bozux")
// add
new_username := &schema.SchemaField{}
if err := json.Unmarshal([]byte(`{
"system": false,
"id": "kvteagv6",
"name": "username",
"type": "text",
"required": false,
"presentable": false,
"unique": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
}`), new_username); err != nil {
return err
}
collection.Schema.AddField(new_username)
// add
new_avatar := &schema.SchemaField{}
if err := json.Unmarshal([]byte(`{
"system": false,
"id": "m9efnpak",
"name": "avatar",
"type": "file",
"required": false,
"presentable": false,
"unique": false,
"options": {
"mimeTypes": [
"image/jpeg",
"image/png",
"image/svg+xml",
"image/gif",
"image/webp"
],
"thumbs": null,
"maxSelect": 1,
"maxSize": 5242880,
"protected": false
}
}`), new_avatar); err != nil {
return err
}
collection.Schema.AddField(new_avatar)
return dao.SaveCollection(collection)
}, func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("xku110v5a5xbufa")
if err != nil {
return err
}
options := map[string]any{}
if err := json.Unmarshal([]byte(`{
"query": "SELECT id, username, avatar FROM users"
}`), &options); err != nil {
return err
}
collection.SetOptions(options)
// add
del_username := &schema.SchemaField{}
if err := json.Unmarshal([]byte(`{
"system": false,
"id": "ogrxf4ps",
"name": "username",
"type": "text",
"required": false,
"presentable": false,
"unique": false,
"options": {
"min": null,
"max": null,
"pattern": ""
}
}`), del_username); err != nil {
return err
}
collection.Schema.AddField(del_username)
// add
del_avatar := &schema.SchemaField{}
if err := json.Unmarshal([]byte(`{
"system": false,
"id": "7k4bozux",
"name": "avatar",
"type": "file",
"required": false,
"presentable": false,
"unique": false,
"options": {
"mimeTypes": [
"image/jpeg",
"image/png",
"image/svg+xml",
"image/gif",
"image/webp"
],
"thumbs": null,
"maxSelect": 1,
"maxSize": 5242880,
"protected": false
}
}`), del_avatar); err != nil {
return err
}
collection.Schema.AddField(del_avatar)
// remove
collection.Schema.RemoveField("kvteagv6")
// remove
collection.Schema.RemoveField("m9efnpak")
return dao.SaveCollection(collection)
})
}

View File

@@ -0,0 +1,34 @@
package migrations
import (
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
m "github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/tools/types"
)
func init() {
m.Register(func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("goeo2ubp103rzp9")
if err != nil {
return err
}
collection.ViewRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.waypoints.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.waypoints.id ?= id && @collection.trails.public ?= true) || \n(@collection.trail_share.trail.waypoints.id ?= id && @collection.trail_share.user ?= @request.auth.id) ||\n(author = @request.auth.id)")
return dao.SaveCollection(collection)
}, func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("goeo2ubp103rzp9")
if err != nil {
return err
}
collection.ViewRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.waypoints.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.waypoints.id ?= id && @collection.trails.public ?= true) || (author = @request.auth.id)")
return dao.SaveCollection(collection)
})
}

View File

@@ -0,0 +1,38 @@
package migrations
import (
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
m "github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/tools/types"
)
func init() {
m.Register(func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
if err != nil {
return err
}
collection.ListRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.summit_logs.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.summit_logs.id ?= id && @collection.trails.public ?= true) ||\n(@collection.trail_share.trail.summit_logs.id ?= id && @collection.trail_share.user ?= @request.auth.id) ||\n(author = @request.auth.id)")
collection.ViewRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.summit_logs.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.summit_logs.id ?= id && @collection.trails.public ?= true) || \n(@collection.trail_share.trail.summit_logs.id ?= id && @collection.trail_share.user ?= @request.auth.id) ||\n(author = @request.auth.id)")
return dao.SaveCollection(collection)
}, func(db dbx.Builder) error {
dao := daos.New(db);
collection, err := dao.FindCollectionByNameOrId("dd2l9a4vxpy2ni8")
if err != nil {
return err
}
collection.ListRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.summit_logs.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.summit_logs.id ?= id && @collection.trails.public ?= true) || (author = @request.auth.id)")
collection.ViewRule = types.Pointer("(@request.auth.id != \"\" && @collection.trails.summit_logs.id ?= id && @collection.trails.author ?= @request.auth.id) || (@collection.trails.summit_logs.id ?= id && @collection.trails.public ?= true) || (author = @request.auth.id)")
return dao.SaveCollection(collection)
})
}

View File

@@ -78,7 +78,7 @@
function handleDropdownClick(item: { text: string; value: any }) { function handleDropdownClick(item: { text: string; value: any }) {
if (item.value == "profile") { if (item.value == "profile") {
goto("/profile"); goto(`/profile/${$currentUser?.id}`);
} else if (item.value == "logout") { } else if (item.value == "logout") {
logout(); logout();
window.location.href = "/"; window.location.href = "/";
@@ -128,7 +128,7 @@
<div class="basis-full"></div> <div class="basis-full"></div>
<hr class="border-input-border" /> <hr class="border-input-border" />
<div class="flex gap-4 items-center justify-between m-4"> <div class="flex gap-4 items-center justify-between m-4">
<a href="/profile"> <a href="/profile/{$currentUser.id}">
<img <img
class="rounded-full w-10 aspect-square" class="rounded-full w-10 aspect-square"
src={getFileURL($currentUser, $currentUser.avatar) || src={getFileURL($currentUser, $currentUser.avatar) ||
@@ -136,7 +136,7 @@
alt="avatar" alt="avatar"
/> />
</a> </a>
<a href="/profile"> <a href="/profile/{$currentUser.id}">
<p class="text-sm">{$currentUser.username}</p> <p class="text-sm">{$currentUser.username}</p>
<p class="text-sm text-gray-500"> <p class="text-sm text-gray-500">
{$currentUser.email} {$currentUser.email}

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import type { List } from "$lib/models/list"; import type { List } from "$lib/models/list";
import type { Trail } from "$lib/models/trail"; import type { Trail } from "$lib/models/trail";
import type { User } from "$lib/models/user"; import type { User, UserAnonymous } from "$lib/models/user";
import { pb } from "$lib/pocketbase"; import { pb } from "$lib/pocketbase";
import { users_show } from "$lib/stores/user_store"; import { users_show } from "$lib/stores/user_store";
import { getFileURL } from "$lib/util/file_util"; import { getFileURL } from "$lib/util/file_util";
@@ -18,7 +18,7 @@
let loading: boolean = false; let loading: boolean = false;
let infoLoaded: boolean = false; let infoLoaded: boolean = false;
let subjectIsOwned: boolean = subject.author == pb.authStore.model?.id; let subjectIsOwned: boolean = subject.author == pb.authStore.model?.id;
let author: User; let author: UserAnonymous;
async function fetchInfo() { async function fetchInfo() {
if (!infoLoaded) { if (!infoLoaded) {

View File

@@ -14,6 +14,7 @@
export let summitLogs: SummitLog[] = []; export let summitLogs: SummitLog[] = [];
export let showCategory: boolean = false; export let showCategory: boolean = false;
export let showTrail: boolean = false; export let showTrail: boolean = false;
export let showAuthor: boolean = false;
let openMapModal: () => void; let openMapModal: () => void;
let closeMapModal: () => void; let closeMapModal: () => void;
@@ -27,9 +28,7 @@
let currentText: string = ""; let currentText: string = "";
onMount(async () => { onMount(async () => {});
});
async function openMap(log: SummitLog) { async function openMap(log: SummitLog) {
if (!log.expand.gpx_data) { if (!log.expand.gpx_data) {
@@ -72,6 +71,11 @@
</th> </th>
{/if} {/if}
<th>{$_("description")}</th> <th>{$_("description")}</th>
{#if showAuthor}
<th>
{$_("author", { values: { n: 1 } })}
</th>
{/if}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -83,6 +87,7 @@
on:text={(e) => openText(e.detail)} on:text={(e) => openText(e.detail)}
{showCategory} {showCategory}
{showTrail} {showTrail}
{showAuthor}
></SummitLogTableRow> ></SummitLogTableRow>
{/each} {/each}
</tbody> </tbody>

View File

@@ -11,11 +11,13 @@
import type { Map } from "leaflet"; import type { Map } from "leaflet";
import { createEventDispatcher, onMount } from "svelte"; import { createEventDispatcher, onMount } from "svelte";
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { getFileURL } from "$lib/util/file_util";
export let index: number; export let index: number;
export let log: SummitLog; export let log: SummitLog;
export let showCategory: boolean = false; export let showCategory: boolean = false;
export let showTrail: boolean = false; export let showTrail: boolean = false;
export let showAuthor: boolean = false;
let map: Map; let map: Map;
@@ -64,13 +66,10 @@
} }
function colCount() { function colCount() {
if (showCategory && showTrail) { return [showCategory, showTrail, showAuthor].reduce(
return 9; (b, v) => (v ? b + 1 : b),
} else if (showCategory || showTrail) { 7,
return 8; );
}
return 7;
} }
</script> </script>
@@ -130,6 +129,26 @@
> >
{/if} {/if}
</td> </td>
{#if showAuthor && log.expand.author}
<td>
<p
class="tooltip flex justify-center"
data-title={log.expand.author.username}
>
<a href="/profile/{log.expand.author.id}">
<img
class="rounded-full w-7 aspect-square"
src={getFileURL(
log.expand?.author,
log.expand?.author.avatar,
) ||
`https://api.dicebear.com/7.x/initials/svg?seed=${log.expand?.author.username}&backgroundType=gradientLinear`}
alt="avatar"
/>
</a>
</p>
</td>
{/if}
</tr> </tr>
<tr> <tr>
<td colspan={colCount()}> <hr class="border-input-border" /> </td> <td colspan={colCount()}> <hr class="border-input-border" /> </td>

View File

@@ -172,7 +172,7 @@
class="trail-info-panel mx-auto {mode == 'list' class="trail-info-panel mx-auto {mode == 'list'
? '' ? ''
: 'border border-input-border rounded-3xl'} h-full" : 'border border-input-border rounded-3xl'} h-full"
style="max-width: min(100%, 64rem);" style="max-width: min(100%, 76rem);"
> >
<div class="trail-info-panel-header"> <div class="trail-info-panel-header">
<section class="relative h-80"> <section class="relative h-80">
@@ -239,7 +239,7 @@
`https://api.dicebear.com/7.x/initials/svg?seed=${trail.expand.author.username}&backgroundType=gradientLinear`} `https://api.dicebear.com/7.x/initials/svg?seed=${trail.expand.author.username}&backgroundType=gradientLinear`}
alt="avatar" alt="avatar"
/> />
{trail.expand.author.username} <a class="underline" href="/profile/{trail.expand.author.id}">{trail.expand.author.username}</a>
</p> </p>
{/if} {/if}
<div class="flex flex-wrap gap-x-8 gap-y-2 mt-4 mr-8"> <div class="flex flex-wrap gap-x-8 gap-y-2 mt-4 mr-8">
@@ -357,8 +357,8 @@
</div> </div>
{/if} {/if}
{#if activeTab == 3} {#if activeTab == 3}
<div class="overflow-x-scroll"> <div class="overflow-x-auto">
<SummitLogTable summitLogs={trail.expand.summit_logs} <SummitLogTable summitLogs={trail.expand.summit_logs} showAuthor
></SummitLogTable> ></SummitLogTable>
</div> </div>
{/if} {/if}

View File

@@ -1,4 +1,5 @@
import type { Trail } from "./trail"; import type { Trail } from "./trail";
import type { UserAnonymous } from "./user";
class SummitLog { class SummitLog {
id?: string; id?: string;
@@ -15,6 +16,7 @@ class SummitLog {
expand: { expand: {
gpx_data?: string; gpx_data?: string;
trails_via_summit_logs?: Trail[]; trails_via_summit_logs?: Trail[];
author?: UserAnonymous
} }
constructor(date: string, params?: { id?: string, text?: string, distance?: number, elevation_loss?: number, elevation_gain?: number, duration?: number }) { constructor(date: string, params?: { id?: string, text?: string, distance?: number, elevation_loss?: number, elevation_gain?: number, duration?: number }) {

View File

@@ -1,4 +1,4 @@
import type { User } from "./user"; import type { User, UserAnonymous } from "./user";
export class TrailShare { export class TrailShare {
id?: string; id?: string;
@@ -6,7 +6,7 @@ export class TrailShare {
trail: string; trail: string;
permission: "view" | "edit" permission: "view" | "edit"
expand?: { expand?: {
user: User user: UserAnonymous
} }
constructor(user: string, trail: string, permission: "view" | "edit") { constructor(user: string, trail: string, permission: "view" | "edit") {

View File

@@ -14,4 +14,5 @@ export type UserAnonymous = {
id: string, id: string,
username?: string, username?: string,
avatar?: string; avatar?: string;
created?: string;
} }

View File

@@ -7,8 +7,10 @@ import { fetchGPX } from "./trail_store";
export const summitLog: Writable<SummitLog> = writable(new SummitLog(new Date().toISOString().substring(0, 10))); export const summitLog: Writable<SummitLog> = writable(new SummitLog(new Date().toISOString().substring(0, 10)));
export const summitLogs: Writable<SummitLog[]> = writable([]); export const summitLogs: Writable<SummitLog[]> = writable([]);
export async function summit_logs_index(filter?: SummitLogFilter, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) { export async function summit_logs_index(author: string, filter?: SummitLogFilter, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
const filterText = filter ? buildFilterText(filter) : "";
let filterText = `author='${author}'`
filterText += filter ? "&&" + buildFilterText(filter) : "";
const r = await f('/api/v1/summit-log?' + new URLSearchParams({ const r = await f('/api/v1/summit-log?' + new URLSearchParams({
filter: filterText, filter: filterText,

View File

@@ -1,4 +1,4 @@
import type { User } from "$lib/models/user"; import type { User, UserAnonymous } from "$lib/models/user";
import { pb } from "$lib/pocketbase"; import { pb } from "$lib/pocketbase";
import { ClientResponseError, type AuthMethodsList } from "pocketbase"; import { ClientResponseError, type AuthMethodsList } from "pocketbase";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
@@ -35,11 +35,11 @@ export async function users_search(q: string, includeSelf: boolean = true) {
} }
} }
export async function users_show(id: string) { export async function users_show(id: string, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
let r = await fetch(`/api/v1/user/anonymous/${id}`, { let r = await f(`/api/v1/user/anonymous/${id}`, {
method: 'GET', method: 'GET',
}) })
const response = await r.json() const response: UserAnonymous = await r.json()
if (r.ok) { if (r.ok) {
return response; return response;

View File

@@ -11,6 +11,16 @@ export async function GET(event: RequestEvent) {
sort: "+date", sort: "+date",
filter: filter filter: filter
}) })
for (const t of r) {
if (!t.author || !pb.authStore.model) {
continue;
}
if (!t.expand) {
t.expand = {} as any
}
t.expand.author = await pb.collection("users_anonymous").getOne(t.author);
}
return json(r) return json(r)
} catch (e: any) { } catch (e: any) {
throw error(e.status, e); throw error(e.status, e);

View File

@@ -7,6 +7,12 @@ export async function GET(event: RequestEvent) {
try { try {
const r = await pb.collection('summit_logs') const r = await pb.collection('summit_logs')
.getOne<SummitLog>(event.params.id as string) .getOne<SummitLog>(event.params.id as string)
if (!r.expand) {
r.expand = {} as any
}
r.expand.author = await pb.collection("users_anonymous").getOne(r.author!);
return json(r) return json(r)
} catch (e: any) { } catch (e: any) {
throw error(e.status, e); throw error(e.status, e);

View File

@@ -21,9 +21,15 @@ export async function GET(event: RequestEvent) {
r.date = r.date?.substring(0, 10) ?? "" r.date = r.date?.substring(0, 10) ?? ""
for (const log of r.expand?.summit_logs ?? []) { for (const log of r.expand?.summit_logs ?? []) {
log.date = log.date.substring(0, 10) log.date = log.date.substring(0, 10)
if (!log.expand) {
log.expand = {} as any
}
log.expand.author = await pb.collection("users_anonymous").getOne(log.author!);
} }
return json(r) return json(r)
} catch (e: any) { } catch (e: any) {
console.error(e)
throw error(e.status || 500, e); throw error(e.status || 500, e);
} }
} }

View File

@@ -218,7 +218,7 @@
} }
async function loadSummitLogs() { async function loadSummitLogs() {
const logs = await summit_logs_index(filter); const logs = await summit_logs_index($page.params.id, filter);
summitLogs.set(logs); summitLogs.set(logs);
} }
</script> </script>
@@ -230,21 +230,21 @@
<div <div
class="grid grid-cols-1 sm:grid-cols-[272px_minmax(0,_1fr)] md:grid-cols-[356px_minmax(0,_1fr)] gap-y-4 max-w-6xl mx-auto" class="grid grid-cols-1 sm:grid-cols-[272px_minmax(0,_1fr)] md:grid-cols-[356px_minmax(0,_1fr)] gap-y-4 max-w-6xl mx-auto"
> >
{#if $currentUser} {#if data.user}
<div class="flex items-center gap-x-6 h-full px-4"> <div class="flex items-center gap-x-6 h-full px-4">
<img <img
class="rounded-full w-16 aspect-square overflow-hidden" class="rounded-full w-16 aspect-square overflow-hidden"
src={getFileURL($currentUser, $currentUser.avatar) || src={getFileURL(data.user, data.user.avatar) ||
`https://api.dicebear.com/7.x/initials/svg?seed=${$currentUser.username}&backgroundType=gradientLinear`} `https://api.dicebear.com/7.x/initials/svg?seed=${data.user.username}&backgroundType=gradientLinear`}
alt="avatar" alt="avatar"
/> />
<div> <div>
<h4 class="text-2xl font-semibold col-start-2"> <h4 class="text-2xl font-semibold col-start-2">
{$currentUser.username} {data.user.username}
</h4> </h4>
<p class="text-sm"> <p class="text-sm">
<span class="text-gray-500">Joined:</span> <span class="text-gray-500">Joined:</span>
{new Date($currentUser.created ?? "").toLocaleDateString( {new Date(data.user.created ?? "").toLocaleDateString(
undefined, undefined,
{ {
month: "2-digit", month: "2-digit",
@@ -420,7 +420,7 @@
<span class="text-gray-500 font-semibold text-lg" <span class="text-gray-500 font-semibold text-lg"
><i class="fa fa-table mr-3"></i>{$_("all-activities")}</span ><i class="fa fa-table mr-3"></i>{$_("all-activities")}</span
> >
<div class=" overflow-x-scroll"> <div class=" overflow-x-auto">
<SummitLogTable summitLogs={$summitLogs} showCategory showTrail <SummitLogTable summitLogs={$summitLogs} showCategory showTrail
></SummitLogTable> ></SummitLogTable>
</div> </div>

View File

@@ -1,10 +1,15 @@
import type { SummitLogFilter } from "$lib/models/summit_log"; import type { SummitLogFilter } from "$lib/models/summit_log";
import { categories_index } from "$lib/stores/category_store"; import { categories_index } from "$lib/stores/category_store";
import { summit_logs_index } from "$lib/stores/summit_log_store"; import { summit_logs_index } from "$lib/stores/summit_log_store";
import { type ServerLoad } from "@sveltejs/kit"; import { users_show } from "$lib/stores/user_store";
import { error, type ServerLoad } from "@sveltejs/kit";
export const load: ServerLoad = async ({ params, locals, fetch }) => { export const load: ServerLoad = async ({ params, locals, fetch }) => {
if(!params.id) {
error(404, "Not found")
}
const date = new Date() const date = new Date()
date.setUTCHours(6) date.setUTCHours(6)
const y = date.getFullYear() const y = date.getFullYear()
@@ -19,7 +24,8 @@ export const load: ServerLoad = async ({ params, locals, fetch }) => {
endDate: lastDay.toISOString().slice(0, 10), endDate: lastDay.toISOString().slice(0, 10),
category: [] category: []
} }
const logs = await summit_logs_index(filter, fetch); const logs = await summit_logs_index(params.id, filter, fetch);
const user = await users_show(params.id, fetch);
return {filter} return { filter, user }
}; };