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
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 false, nil

View File

@ -128,7 +128,6 @@ func setupAnalysisRoute(i InfoType, r *http.Request) InfoType {
func setupTaglistRoute(i InfoType, r *http.Request) InfoType {
jobRepo := repository.GetJobRepository()
tags, counts, err := jobRepo.CountTags(r.Context())
tagMap := make(map[string][]map[string]interface{})
if err != nil {
@ -136,17 +135,34 @@ func setupTaglistRoute(i InfoType, r *http.Request) InfoType {
i["tagmap"] = tagMap
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
for _, tag := range tags {
tagItem := map[string]interface{}{
"id": tag.ID,
"name": tag.Name,
"scope": tag.Scope,
"count": counts[fmt.Sprint(tag.Name, tag.ID)],
if userAuthlevel >= 4 { // Support+ : Show tags for all scopes, regardless of count
for _, tag := range tags {
tagItem := map[string]interface{}{
"id": tag.ID,
"name": tag.Name,
"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
return i
}

View File

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