From 5ba84efab6e797649476943d120da7a167cb9339 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Mon, 19 Jun 2023 17:59:44 +0200 Subject: [PATCH 1/3] User and Project List with 30d filter plus label - Readable labels for other quick select ranges also - Note: URL not reformatted for copy-bility --- web/frontend/src/List.root.svelte | 10 ++++ web/frontend/src/filters/Filters.svelte | 79 +++++++++++-------------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/web/frontend/src/List.root.svelte b/web/frontend/src/List.root.svelte index 814a7df..57cd291 100644 --- a/web/frontend/src/List.root.svelte +++ b/web/frontend/src/List.root.svelte @@ -24,6 +24,16 @@ export let type; export let filterPresets; + // By default, look at the jobs of the last 30 days: + if (filterPresets?.startTime == null) { + if (filterPresets == null) + filterPresets = {} + + const lastMonth = (new Date(Date.now() - (30*24*60*60*1000))).toISOString() + const now = (new Date(Date.now())).toISOString() + filterPresets.startTime = { from: lastMonth, to: now, text: 'Last 30 Days', url: 'last30d' } + } + console.assert( type == "USER" || type == "PROJECT", "Invalid list type provided!" diff --git a/web/frontend/src/filters/Filters.svelte b/web/frontend/src/filters/Filters.svelte index b8264d3..1431293 100644 --- a/web/frontend/src/filters/Filters.svelte +++ b/web/frontend/src/filters/Filters.svelte @@ -35,17 +35,17 @@ projectMatch: filterPresets.projectMatch || 'contains', userMatch: filterPresets.userMatch || 'contains', - cluster: filterPresets.cluster || null, - partition: filterPresets.partition || null, - states: filterPresets.states || filterPresets.state ? [filterPresets.state].flat() : allJobStates, - startTime: filterPresets.startTime || { from: null, to: null }, - tags: filterPresets.tags || [], - duration: filterPresets.duration || { from: null, to: null }, - jobId: filterPresets.jobId || '', - arrayJobId: filterPresets.arrayJobId || null, - user: filterPresets.user || '', - project: filterPresets.project || '', - jobName: filterPresets.jobName || '', + cluster: filterPresets.cluster || null, + partition: filterPresets.partition || null, + states: filterPresets.states || filterPresets.state ? [filterPresets.state].flat() : allJobStates, + startTime: filterPresets.startTime || { from: null, to: null }, + tags: filterPresets.tags || [], + duration: filterPresets.duration || { from: null, to: null }, + jobId: filterPresets.jobId || '', + arrayJobId: filterPresets.arrayJobId || null, + user: filterPresets.user || '', + project: filterPresets.project || '', + jobName: filterPresets.jobName || '', numNodes: filterPresets.numNodes || { from: null, to: null }, numHWThreads: filterPresets.numHWThreads || { from: null, to: null }, @@ -120,7 +120,11 @@ for (let state of filters.states) opts.push(`state=${state}`) if (filters.startTime.from && filters.startTime.to) - opts.push(`startTime=${dateToUnixEpoch(filters.startTime.from)}-${dateToUnixEpoch(filters.startTime.to)}`) + // if (filters.startTime.url) { + // opts.push(`startTime=${filters.startTime.url}`) + // } else { + opts.push(`startTime=${dateToUnixEpoch(filters.startTime.from)}-${dateToUnixEpoch(filters.startTime.to)}`) + // } for (let tag of filters.tags) opts.push(`tag=${tag}`) if (filters.duration.from && filters.duration.to) @@ -193,16 +197,18 @@ Start Time Qick Selection {#each [ - { text: 'Last 6hrs', seconds: 6*60*60 }, - { text: 'Last 12hrs', seconds: 12*60*60 }, - { text: 'Last 24hrs', seconds: 24*60*60 }, - { text: 'Last 48hrs', seconds: 48*60*60 }, - { text: 'Last 7 days', seconds: 7*24*60*60 }, - { text: 'Last 30 days', seconds: 30*24*60*60 } - ] as {text, seconds}} + { text: 'Last 6hrs', url: 'last6h', seconds: 6*60*60 }, + // { text: 'Last 12hrs', seconds: 12*60*60 }, + { text: 'Last 24hrs', url: 'last24h', seconds: 24*60*60 }, + // { text: 'Last 48hrs', seconds: 48*60*60 }, + { text: 'Last 7 days', url: 'last7d', seconds: 7*24*60*60 }, + { text: 'Last 30 days', url: 'last30d', seconds: 30*24*60*60 } + ] as {text, url, seconds}} { filters.startTime.from = (new Date(Date.now() - seconds * 1000)).toISOString() filters.startTime.to = (new Date(Date.now())).toISOString() + filters.startTime.text = text, + filters.startTime.url = url update() }}> {text} @@ -212,27 +218,6 @@ - {#if filters.cluster} (isClusterOpen = true)}> @@ -251,8 +236,12 @@ {#if filters.startTime.from || filters.startTime.to} (isStartTimeOpen = true)}> - {new Date(filters.startTime.from).toLocaleString()} - {new Date(filters.startTime.to).toLocaleString()} - + {#if filters.startTime.text} + {filters.startTime.text} + {:else} + {new Date(filters.startTime.from).toLocaleString()} - {new Date(filters.startTime.to).toLocaleString()} + {/if} + {/if} {#if filters.duration.from || filters.duration.to} @@ -307,7 +296,11 @@ bind:isOpen={isStartTimeOpen} bind:from={filters.startTime.from} bind:to={filters.startTime.to} - on:update={() => update()} /> + on:update={() => { + delete filters.startTime['text'] + delete filters.startTime['url'] + update() + }} /> Date: Tue, 20 Jun 2023 07:55:57 +0200 Subject: [PATCH 2/3] Add hook for frontend build --- .goreleaser.yaml | 8 ++++++-- Makefile | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 8400874..eaf9881 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -4,7 +4,7 @@ before: - go mod tidy builds: - env: - - CGO_ENABLED=0 + - CGO_ENABLED=1 goos: - linux - darwin @@ -12,7 +12,6 @@ builds: - amd64 - arm64 goamd64: - - v2 - v3 goarm: - "7" @@ -20,6 +19,11 @@ builds: main: ./cmd/cc-backend tags: - static_build + hooks: + pre: make frontend + ignore: + - goos: linux + goarch: arm64 archives: - format: tar.gz diff --git a/Makefile b/Makefile index 032559b..455ce3c 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ SVELTE_SRC = $(wildcard $(FRONTEND)/src/*.svelte) \ $(wildcard $(FRONTEND)/src/plots/*.svelte) \ $(wildcard $(FRONTEND)/src/joblist/*.svelte) -.PHONY: clean test tags $(TARGET) +.PHONY: clean test tags frontend $(TARGET) .NOTPARALLEL: @@ -36,6 +36,10 @@ $(TARGET): $(VAR) $(CFG) $(SVELTE_TARGETS) $(info ===> BUILD cc-backend) @go build -ldflags=${LD_FLAGS} ./cmd/cc-backend +frontend: + $(info ===> BUILD frontend) + cd web/frontend && npm install && npm run build + clean: $(info ===> CLEAN) @go clean From c973a2973456ce352c6857ddd4602c252cd25877 Mon Sep 17 00:00:00 2001 From: Jan Eitzinger Date: Tue, 20 Jun 2023 12:54:26 +0200 Subject: [PATCH 3/3] Restore api role access in SecurityCheck --- internal/api/rest.go | 1 + internal/repository/query.go | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/internal/api/rest.go b/internal/api/rest.go index b66a561..da37a25 100644 --- a/internal/api/rest.go +++ b/internal/api/rest.go @@ -192,6 +192,7 @@ func decode(r io.Reader, val interface{}) error { // @security ApiKeyAuth // @router /jobs/ [get] func (api *RestApi) getJobs(rw http.ResponseWriter, r *http.Request) { + if user := auth.GetUser(r.Context()); user != nil && !user.HasRole(auth.RoleApi) { handleError(fmt.Errorf("missing role: %v", auth.GetRoleString(auth.RoleApi)), http.StatusForbidden, rw) return diff --git a/internal/repository/query.go b/internal/repository/query.go index 32ecea0..ba1d1d7 100644 --- a/internal/repository/query.go +++ b/internal/repository/query.go @@ -81,8 +81,7 @@ func (r *JobRepository) testQueryJobs( page *model.PageRequest, order *model.OrderByInput) ([]*schema.Job, error) { - return r.queryJobs(sq.Select(jobColumns...).From("job"), - filters, page, order) + return r.queryJobs(sq.Select(jobColumns...).From("job"), filters, page, order) } // Public function with added securityCheck, calls private queryJobs function above @@ -98,8 +97,7 @@ func (r *JobRepository) QueryJobs( return nil, qerr } - return r.queryJobs(query, - filters, page, order) + return r.queryJobs(query, filters, page, order) } // SecurityCheck-less, private: returns a list of minimal job information (DB-ID and jobId) of shared jobs for link-building based the provided filters. @@ -202,12 +200,12 @@ func (r *JobRepository) CountJobs( return r.countJobs(query, filters) } -func SecurityCheck(ctx context.Context, query sq.SelectBuilder) (queryOut sq.SelectBuilder, err error) { +func SecurityCheck(ctx context.Context, query sq.SelectBuilder) (sq.SelectBuilder, error) { user := auth.GetUser(ctx) if user == nil { var qnil sq.SelectBuilder return qnil, fmt.Errorf("user context is nil!") - } else if user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport}) { // Admin & Co. : All jobs + } else if user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport, auth.RoleApi}) { // Admin & Co. : All jobs return query, nil } else if user.HasRole(auth.RoleManager) { // Manager : Add filter for managed projects' jobs only + personal jobs if len(user.Projects) != 0 {