filter taglist scope visibility by role, add global tag handling to support role

This commit is contained in:
Christoph Kluge 2024-10-09 13:23:06 +02:00
parent bc434ee8cb
commit e3104c61cb
3 changed files with 46 additions and 26 deletions

View File

@ -309,7 +309,7 @@ func (r *JobRepository) checkScopeAuth(ctx context.Context, operation string, sc
} }
return false, nil return false, nil
case operation == "write" && scope == "global": case operation == "write" && scope == "global":
if user.HasRole(schema.RoleAdmin) || (len(user.Roles) == 1 && user.HasRole(schema.RoleApi)) { if user.HasAnyRole([]schema.Role{schema.RoleAdmin, schema.RoleSupport}) || (len(user.Roles) == 1 && user.HasRole(schema.RoleApi)) {
return true, nil return true, nil
} }
return false, nil return false, nil

View File

@ -128,7 +128,6 @@ func setupAnalysisRoute(i InfoType, r *http.Request) InfoType {
func setupTaglistRoute(i InfoType, r *http.Request) InfoType { func setupTaglistRoute(i InfoType, r *http.Request) InfoType {
jobRepo := repository.GetJobRepository() jobRepo := repository.GetJobRepository()
tags, counts, err := jobRepo.CountTags(r.Context()) tags, counts, err := jobRepo.CountTags(r.Context())
tagMap := make(map[string][]map[string]interface{}) tagMap := make(map[string][]map[string]interface{})
if err != nil { if err != nil {
@ -136,17 +135,34 @@ func setupTaglistRoute(i InfoType, r *http.Request) InfoType {
i["tagmap"] = tagMap i["tagmap"] = tagMap
return i return i
} }
// Reduces displayed tags for unauth'd users
userAuthlevel := repository.GetUserFromContext(r.Context()).GetAuthLevel()
// Uses tag.ID as second Map-Key component to differentiate tags with identical names // Uses tag.ID as second Map-Key component to differentiate tags with identical names
for _, tag := range tags { if userAuthlevel >= 4 { // Support+ : Show tags for all scopes, regardless of count
tagItem := map[string]interface{}{ for _, tag := range tags {
"id": tag.ID, tagItem := map[string]interface{}{
"name": tag.Name, "id": tag.ID,
"scope": tag.Scope, "name": tag.Name,
"count": counts[fmt.Sprint(tag.Name, tag.ID)], "scope": tag.Scope,
"count": counts[fmt.Sprint(tag.Name, tag.ID)],
}
tagMap[tag.Type] = append(tagMap[tag.Type], tagItem)
} }
tagMap[tag.Type] = append(tagMap[tag.Type], tagItem) } else if userAuthlevel < 4 && userAuthlevel >= 2 { // User+ : Show global and admin scope only if at least 1 tag used, private scope regardless of count
} for _, tag := range tags {
tagCount := counts[fmt.Sprint(tag.Name, tag.ID)]
if ((tag.Scope == "global" || tag.Scope == "admin") && tagCount >= 1) || (tag.Scope != "global" && tag.Scope != "admin") {
tagItem := map[string]interface{}{
"id": tag.ID,
"name": tag.Name,
"scope": tag.Scope,
"count": tagCount,
}
tagMap[tag.Type] = append(tagMap[tag.Type], tagItem)
}
}
} // auth < 2 return nothing for this route
i["tagmap"] = tagMap i["tagmap"] = tagMap
return i return i
} }

View File

@ -48,7 +48,8 @@
let filterTerm = ""; let filterTerm = "";
let pendingChange = false; let pendingChange = false;
let isOpen = false; let isOpen = false;
const isAdmin = (roles && authlevel >= roles.admin); const isAdmin = (roles && authlevel == roles.admin);
const isSupport = (roles && authlevel == roles.support);
const client = getContextClient(); const client = getContextClient();
@ -104,8 +105,8 @@
}; };
$: allTagsFiltered = ($initialized, fuzzySearchTags(filterTerm, allTags)); $: allTagsFiltered = ($initialized, fuzzySearchTags(filterTerm, allTags));
$: usedTagsFiltered = matchJobTags(jobTags, allTagsFiltered, 'used', isAdmin); $: usedTagsFiltered = matchJobTags(jobTags, allTagsFiltered, 'used', isAdmin, isSupport);
$: unusedTagsFiltered = matchJobTags(jobTags, allTagsFiltered, 'unused', isAdmin); $: unusedTagsFiltered = matchJobTags(jobTags, allTagsFiltered, 'unused', isAdmin, isSupport);
$: { $: {
newTagType = ""; newTagType = "";
@ -117,16 +118,17 @@
} }
} }
function matchJobTags(tags, availableTags, type, isAdmin) { function matchJobTags(tags, availableTags, type, isAdmin, isSupport) {
const jobTagIds = tags.map((t) => t.id) const jobTagIds = tags.map((t) => t.id)
if (type == 'used') { if (isAdmin || type == 'used') { // Always show used tags, admin also show all unused
return availableTags.filter((at) => jobTagIds.includes(at.id)) return availableTags.filter((at) => jobTagIds.includes(at.id))
} else if (type == 'unused' && isAdmin) { } else { // ... for unused
return availableTags.filter((at) => !jobTagIds.includes(at.id)) if (isSupport) { // ... show global tags for support
} else if (type == 'unused' && !isAdmin) { // Normal Users should not see unused global tags here return availableTags.filter((at) => !jobTagIds.includes(at.id) && at.scope !== "admin")
return availableTags.filter((at) => !jobTagIds.includes(at.id) && at.scope !== "global") } else { // ... show only private tags for user, manager
return availableTags.filter((at) => !jobTagIds.includes(at.id) && at.scope !== "admin" && at.scope !== "global")
}
} }
return []
} }
function isNewTag(type, name) { function isNewTag(type, name) {
@ -223,7 +225,7 @@
Private Tag Private Tag
{/if} {/if}
</Button> </Button>
{#if isAdmin || (utag.scope !== 'global' && utag.scope !== 'admin')} {#if isAdmin || (isSupport && utag.scope == 'global') || (utag.scope !== 'global' && utag.scope !== 'admin')}
<Button <Button
size="sm" size="sm"
color="danger" color="danger"
@ -273,7 +275,7 @@
Private Tag Private Tag
{/if} {/if}
</Button> </Button>
{#if isAdmin || (uutag.scope !== 'global' && uutag.scope !== 'admin')} {#if isAdmin || (isSupport && uutag.scope == 'global') || (uutag.scope !== 'global' && uutag.scope !== 'admin')}
<Button <Button
size="sm" size="sm"
color="success" color="success"
@ -304,7 +306,7 @@
{#if newTagType && newTagName && isNewTag(newTagType, newTagName)} {#if newTagType && newTagName && isNewTag(newTagType, newTagName)}
<Row> <Row>
<Col xs={isAdmin ? 7 : 12} md={12} lg={isAdmin ? 7 : 12} xl={12} xxl={isAdmin ? 7 : 12} class="mb-2"> <Col xs={(isAdmin || isSupport) ? 7 : 12} md={12} lg={(isAdmin || isSupport) ? 7 : 12} xl={12} xxl={(isAdmin || isSupport) ? 7 : 12} class="mb-2">
<Button <Button
outline outline
style="width:100%;" style="width:100%;"
@ -317,12 +319,14 @@
<Tag tag={{ type: newTagType, name: newTagName, scope: newTagScope }} clickable={false}/> <Tag tag={{ type: newTagType, name: newTagName, scope: newTagScope }} clickable={false}/>
</Button> </Button>
</Col> </Col>
{#if isAdmin} {#if isSupport || isAdmin}
<Col xs={5} md={12} lg={5} xl={12} xxl={5} class="mb-2" style="align-content:center;"> <Col xs={5} md={12} lg={5} xl={12} xxl={5} class="mb-2" style="align-content:center;">
<Input type="select" bind:value={newTagScope}> <Input type="select" bind:value={newTagScope}>
<option value={username}>Scope: Private</option> <option value={username}>Scope: Private</option>
<option value={"global"}>Scope: Global</option> <option value={"global"}>Scope: Global</option>
<option value={"admin"}>Scope: Admin</option> {#if isAdmin}
<option value={"admin"}>Scope: Admin</option>
{/if}
</Input> </Input>
</Col> </Col>
{/if} {/if}