mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-11-04 01:25:06 +01:00 
			
		
		
		
	@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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!"
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,11 @@
 | 
			
		||||
            for (let state of filters.states)
 | 
			
		||||
                opts.push(`state=${state}`)
 | 
			
		||||
        if (filters.startTime.from && 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 @@
 | 
			
		||||
                    <DropdownItem divider/>
 | 
			
		||||
                    <DropdownItem disabled>Start Time Qick Selection</DropdownItem>
 | 
			
		||||
                    {#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}}
 | 
			
		||||
                        <DropdownItem on:click={() => {
 | 
			
		||||
                            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()
 | 
			
		||||
                        }}>
 | 
			
		||||
                            <Icon name="calendar-range"/> {text}
 | 
			
		||||
@@ -212,27 +218,6 @@
 | 
			
		||||
            </DropdownMenu>
 | 
			
		||||
        </ButtonDropdown>
 | 
			
		||||
    </Col>
 | 
			
		||||
    <!-- {#if startTimeQuickSelect}
 | 
			
		||||
        <Col xs="auto">
 | 
			
		||||
            <TimeSelection customEnabled={false} anyEnabled={true}
 | 
			
		||||
                from={filters.startTime.from ? new Date(filters.startTime.from) : null}
 | 
			
		||||
                to={filters.startTime.to ? new Date(filters.startTime.to) : null}
 | 
			
		||||
                options={{
 | 
			
		||||
                    'Last 6hrs': 6*60*60,
 | 
			
		||||
                    'Last 12hrs': 12*60*60,
 | 
			
		||||
                    'Last 24hrs': 24*60*60,
 | 
			
		||||
                    'Last 48hrs': 48*60*60,
 | 
			
		||||
                    'Last 7 days': 7*24*60*60,
 | 
			
		||||
                    'Last 30 days': 30*24*60*60}}
 | 
			
		||||
                on:change={({ detail: { from, to } }) => {
 | 
			
		||||
                    filters.startTime.from = from?.toISOString()
 | 
			
		||||
                    filters.startTime.to = to?.toISOString()
 | 
			
		||||
                    // console.log(filters.startTime)
 | 
			
		||||
                    update()
 | 
			
		||||
                }}
 | 
			
		||||
                />
 | 
			
		||||
        </Col>
 | 
			
		||||
    {/if} -->
 | 
			
		||||
    <Col xs="auto">
 | 
			
		||||
        {#if filters.cluster}
 | 
			
		||||
            <Info icon="cpu" on:click={() => (isClusterOpen = true)}>
 | 
			
		||||
@@ -251,7 +236,11 @@
 | 
			
		||||
 | 
			
		||||
        {#if filters.startTime.from || filters.startTime.to}
 | 
			
		||||
            <Info icon="calendar-range" on:click={() => (isStartTimeOpen = true)}>
 | 
			
		||||
                {#if filters.startTime.text}
 | 
			
		||||
                    {filters.startTime.text}
 | 
			
		||||
                {:else}
 | 
			
		||||
                    {new Date(filters.startTime.from).toLocaleString()} - {new Date(filters.startTime.to).toLocaleString()}
 | 
			
		||||
                {/if}
 | 
			
		||||
             </Info>
 | 
			
		||||
        {/if}
 | 
			
		||||
 | 
			
		||||
@@ -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()
 | 
			
		||||
    }} />
 | 
			
		||||
 | 
			
		||||
<Duration
 | 
			
		||||
    bind:isOpen={isDurationOpen}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user