diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/DashboardResource.scala b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/DashboardResource.scala index 3410852f981..30427154d8b 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/DashboardResource.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/DashboardResource.scala @@ -620,10 +620,12 @@ class DashboardResource { if (resourceType == "file") { DashboardFile( record.into(USER).getEmail, - record.get( - "user_file_access", - classOf[UserFileAccessPrivilege] - ) == UserFileAccessPrivilege.WRITE, + record + .get( + "user_file_access", + classOf[UserFileAccessPrivilege] + ) + .toString, record.into(FILE).into(classOf[File]) ) } else { diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/file/UserFileAccessResource.scala b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/file/UserFileAccessResource.scala index 2ff4193c9cb..6073d85fdf7 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/file/UserFileAccessResource.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/file/UserFileAccessResource.scala @@ -1,7 +1,6 @@ package edu.uci.ics.texera.web.resource.dashboard.user.file import edu.uci.ics.texera.web.SqlServer -import edu.uci.ics.texera.web.auth.SessionUser import edu.uci.ics.texera.web.model.common.AccessEntry import edu.uci.ics.texera.web.model.jooq.generated.Tables.{ FILE, @@ -18,12 +17,10 @@ import edu.uci.ics.texera.web.model.jooq.generated.tables.daos.{ } import edu.uci.ics.texera.web.model.jooq.generated.tables.pojos.{FileOfWorkflow, UserFileAccess} import edu.uci.ics.texera.web.resource.dashboard.user.file.UserFileAccessResource.{ - checkWriteAccess, context, fileDao, userDao } -import io.dropwizard.auth.Auth import org.jooq.DSLContext import org.jooq.types.UInteger @@ -73,46 +70,6 @@ object UserFileAccessResource { None } } - - /** - * Identifies whether the given user has read-only access over the given workflow - * @param fid file id - * @param uid user id, works with file id as primary keys in database - */ - def checkReadAccess(fid: UInteger, uid: UInteger): Unit = { - if ( - !(getPrivilege(fid, uid).eq(UserFileAccessPrivilege.READ) || getPrivilege(fid, uid).eq( - UserFileAccessPrivilege.WRITE - )) - ) { - throw new ForbiddenException("No sufficient access privilege.") - } - } - - /** - * Identifies whether the given user has write access over the given workflow - * @param fid file id - * @param uid user id, works with file id as primary keys in database - */ - def checkWriteAccess(fid: UInteger, uid: UInteger): Unit = { - if (!getPrivilege(fid, uid).eq(UserFileAccessPrivilege.WRITE)) { - throw new ForbiddenException("No sufficient access privilege.") - } - } - - /** - * @param fid file id - * @param uid user id, works with file id as primary keys in database - * @return UserFileAccessPrivilege value indicating NONE/READ/WRITE - */ - private def getPrivilege(fid: UInteger, uid: UInteger): UserFileAccessPrivilege = { - context - .select() - .from(USER_FILE_ACCESS) - .where(USER_FILE_ACCESS.FID.eq(fid).and(USER_FILE_ACCESS.UID.eq(uid))) - .fetchOneInto(classOf[UserFileAccess]) - .getPrivilege - } } @Produces(Array(MediaType.APPLICATION_JSON)) @RolesAllowed(Array("REGULAR", "ADMIN")) @@ -129,8 +86,7 @@ class UserFileAccessResource { @GET @Path("/owner/{fid}") def getOwner(@PathParam("fid") fid: UInteger): String = { - val uid = fileDao.fetchOneByFid(fid).getOwnerUid - userDao.fetchOneByUid(uid).getEmail + userDao.fetchOneByUid(fileDao.fetchOneByFid(fid).getOwnerUid).getEmail } /** @@ -142,8 +98,7 @@ class UserFileAccessResource { @GET @Path("list/{fid}") def getAccessList( - @PathParam("fid") fid: UInteger, - @Auth user: SessionUser + @PathParam("fid") fid: UInteger ): util.List[AccessEntry] = { context .select( @@ -157,7 +112,7 @@ class UserFileAccessResource { .where( USER_FILE_ACCESS.FID .eq(fid) - .and(USER_FILE_ACCESS.UID.notEqual(user.getUid)) + .and(USER_FILE_ACCESS.UID.notEqual(fileDao.fetchOneByFid(fid).getOwnerUid)) ) .fetchInto(classOf[AccessEntry]) } @@ -175,10 +130,8 @@ class UserFileAccessResource { def grantAccess( @PathParam("fid") fid: UInteger, @PathParam("email") email: String, - @PathParam("privilege") privilege: String, - @Auth user: SessionUser + @PathParam("privilege") privilege: String ): Unit = { - checkWriteAccess(fid, user.getUid) userFileAccessDao.merge( new UserFileAccess( userDao.fetchOneByEmail(email).getUid, @@ -197,13 +150,10 @@ class UserFileAccessResource { */ @DELETE @Path("/revoke/{fid}/{email}") - @RolesAllowed(Array("REGULAR", "ADMIN")) def revokeAccess( @PathParam("fid") fid: UInteger, - @PathParam("email") email: String, - @Auth user: SessionUser + @PathParam("email") email: String ): Unit = { - checkWriteAccess(fid, user.getUid) context .delete(USER_FILE_ACCESS) .where( diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/file/UserFileResource.scala b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/file/UserFileResource.scala index 2eb6f261df2..64bab16c79a 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/file/UserFileResource.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/file/UserFileResource.scala @@ -7,10 +7,6 @@ import edu.uci.ics.texera.web.model.jooq.generated.Tables._ import edu.uci.ics.texera.web.model.jooq.generated.enums.UserFileAccessPrivilege import edu.uci.ics.texera.web.model.jooq.generated.tables.daos.{FileDao, UserFileAccessDao} import edu.uci.ics.texera.web.model.jooq.generated.tables.pojos.{File, User, UserFileAccess} -import edu.uci.ics.texera.web.resource.dashboard.user.file.UserFileAccessResource.{ - checkReadAccess, - checkWriteAccess -} import edu.uci.ics.texera.web.resource.dashboard.user.file.UserFileResource.{ DashboardFile, context, @@ -66,7 +62,7 @@ object UserFileResource { case class DashboardFile( ownerEmail: String, - writeAccess: Boolean, + accessLevel: String, file: File ) } @@ -116,7 +112,7 @@ class UserFileResource { fids += fileRecord.into(FILE).getFid fileEntries += DashboardFile( fileRecord.into(USER).getEmail, - fileRecord.into(USER_FILE_ACCESS).getPrivilege == UserFileAccessPrivilege.WRITE, + fileRecord.into(USER_FILE_ACCESS).getPrivilege.toString, fileRecord.into(FILE).into(classOf[File]) ) }) @@ -136,7 +132,7 @@ class UserFileResource { if (!fileEntries.exists(file => { file.file.getFid == fileRecord.into(FILE).getFid })) { fileEntries += DashboardFile( fileRecord.into(USER).getEmail, - writeAccess = false, + "READ", fileRecord.into(FILE).into(classOf[File]) ) } @@ -183,7 +179,6 @@ class UserFileResource { @PathParam("fid") fid: UInteger, @Auth user: SessionUser ): Unit = { - checkWriteAccess(fid, user.getUid) Files.deleteIfExists(Paths.get(fileDao.fetchOneByFid(fid).getPath)) fileDao.deleteById(fid) } @@ -194,7 +189,6 @@ class UserFileResource { @PathParam("fid") fid: UInteger, @Auth user: SessionUser ): Response = { - checkReadAccess(fid, user.getUid) Response .ok( new StreamingOutput() { @@ -220,7 +214,6 @@ class UserFileResource { @PathParam("name") name: String, @Auth user: SessionUser ): Unit = { - checkWriteAccess(fid, user.getUid) val validationRes = this.validateFileName(name, user.getUid) if (!validationRes.getLeft) { throw new BadRequestException(validationRes.getRight) @@ -235,10 +228,8 @@ class UserFileResource { @Path("/description/{fid}/{description}") def changeFileDescription( @PathParam("fid") fid: UInteger, - @PathParam("description") description: String, - @Auth user: SessionUser + @PathParam("description") description: String ): Unit = { - checkWriteAccess(fid, user.getUid) val userFile = fileDao.fetchOneByFid(fid) userFile.setDescription(description) fileDao.update(userFile) diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/project/ProjectAccessResource.scala b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/project/ProjectAccessResource.scala index 553a7185bf5..930b054b2a9 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/project/ProjectAccessResource.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/project/ProjectAccessResource.scala @@ -1,6 +1,5 @@ package edu.uci.ics.texera.web.resource.dashboard.user.project import edu.uci.ics.texera.web.SqlServer -import edu.uci.ics.texera.web.auth.SessionUser import edu.uci.ics.texera.web.model.common.AccessEntry import edu.uci.ics.texera.web.model.jooq.generated.Tables.{PROJECT_USER_ACCESS, USER} import edu.uci.ics.texera.web.model.jooq.generated.enums.ProjectUserAccessPrivilege @@ -10,7 +9,6 @@ import edu.uci.ics.texera.web.model.jooq.generated.tables.daos.{ UserDao } import edu.uci.ics.texera.web.model.jooq.generated.tables.pojos.ProjectUserAccess -import io.dropwizard.auth.Auth import org.jooq.DSLContext import org.jooq.types.UInteger import java.util @@ -46,8 +44,7 @@ class ProjectAccessResource() { @GET @Path("/list/{pid}") def getAccessList( - @PathParam("pid") pid: UInteger, - @Auth user: SessionUser + @PathParam("pid") pid: UInteger ): util.List[AccessEntry] = { context .select( @@ -58,7 +55,11 @@ class ProjectAccessResource() { .from(PROJECT_USER_ACCESS) .join(USER) .on(USER.UID.eq(PROJECT_USER_ACCESS.UID)) - .where(PROJECT_USER_ACCESS.PID.eq(pid).and(PROJECT_USER_ACCESS.UID.notEqual(user.getUid))) + .where( + PROJECT_USER_ACCESS.PID + .eq(pid) + .and(PROJECT_USER_ACCESS.UID.notEqual(projectDao.fetchOneByPid(pid).getOwnerId)) + ) .fetchInto(classOf[AccessEntry]) } diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/project/ProjectResource.scala b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/project/ProjectResource.scala index ca1b2512049..64516489abb 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/project/ProjectResource.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/project/ProjectResource.scala @@ -3,10 +3,7 @@ package edu.uci.ics.texera.web.resource.dashboard.user.project import edu.uci.ics.texera.web.SqlServer import edu.uci.ics.texera.web.auth.SessionUser import edu.uci.ics.texera.web.model.jooq.generated.Tables._ -import edu.uci.ics.texera.web.model.jooq.generated.enums.{ - ProjectUserAccessPrivilege, - UserFileAccessPrivilege -} +import edu.uci.ics.texera.web.model.jooq.generated.enums.ProjectUserAccessPrivilege import edu.uci.ics.texera.web.model.jooq.generated.tables.daos.{ FileOfProjectDao, ProjectDao, @@ -21,7 +18,6 @@ import edu.uci.ics.texera.web.resource.dashboard.user.workflow.WorkflowResource. import io.dropwizard.auth.Auth import org.apache.commons.lang3.StringUtils -import org.jooq.impl.DSL.case_ import org.jooq.types.UInteger import java.sql.Timestamp import java.util @@ -105,7 +101,7 @@ object ProjectResource { ownerID: UInteger, creationTime: Timestamp, color: String, - writeAccess: Boolean + accessLevel: String ) } @@ -141,8 +137,7 @@ class ProjectResource { PROJECT.OWNER_ID, PROJECT.CREATION_TIME, PROJECT.COLOR, - case_() - .when(PROJECT_USER_ACCESS.PRIVILEGE.eq(ProjectUserAccessPrivilege.WRITE), "true") + PROJECT_USER_ACCESS.PRIVILEGE ) .from(PROJECT) .leftJoin(PROJECT_USER_ACCESS) @@ -221,7 +216,7 @@ class ProjectResource { .map(fileRecord => DashboardFile( fileRecord.into(USER).getName, - fileRecord.into(USER_FILE_ACCESS).getPrivilege == UserFileAccessPrivilege.WRITE, + fileRecord.into(USER_FILE_ACCESS).getPrivilege.toString, fileRecord.into(FILE).into(classOf[File]) ) ) diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/workflow/WorkflowAccessResource.scala b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/workflow/WorkflowAccessResource.scala index 153202f3a79..77de5a45634 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/workflow/WorkflowAccessResource.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/workflow/WorkflowAccessResource.scala @@ -1,7 +1,6 @@ package edu.uci.ics.texera.web.resource.dashboard.user.workflow import edu.uci.ics.texera.web.SqlServer -import edu.uci.ics.texera.web.auth.SessionUser import edu.uci.ics.texera.web.model.common.AccessEntry import edu.uci.ics.texera.web.model.jooq.generated.Tables.{ PROJECT_USER_ACCESS, @@ -16,14 +15,9 @@ import edu.uci.ics.texera.web.model.jooq.generated.tables.daos.{ WorkflowUserAccessDao } import edu.uci.ics.texera.web.model.jooq.generated.tables.pojos.WorkflowUserAccess -import edu.uci.ics.texera.web.resource.dashboard.user.workflow.WorkflowAccessResource.{ - context, - hasWriteAccess -} -import io.dropwizard.auth.Auth +import edu.uci.ics.texera.web.resource.dashboard.user.workflow.WorkflowAccessResource.context import org.jooq.DSLContext import org.jooq.types.UInteger - import java.util import javax.annotation.security.RolesAllowed import javax.ws.rs._ @@ -98,8 +92,7 @@ class WorkflowAccessResource() { @GET @Path("/owner/{wid}") def getOwner(@PathParam("wid") wid: UInteger): String = { - val uid = workflowOfUserDao.fetchByWid(wid).get(0).getUid - userDao.fetchOneByUid(uid).getEmail + userDao.fetchOneByUid(workflowOfUserDao.fetchByWid(wid).get(0).getUid).getEmail } /** @@ -111,8 +104,7 @@ class WorkflowAccessResource() { @GET @Path("/list/{wid}") def getAccessList( - @PathParam("wid") wid: UInteger, - @Auth sessionUser: SessionUser + @PathParam("wid") wid: UInteger ): util.List[AccessEntry] = { context .select( @@ -126,7 +118,7 @@ class WorkflowAccessResource() { .where( WORKFLOW_USER_ACCESS.WID .eq(wid) - .and(WORKFLOW_USER_ACCESS.UID.notEqual(sessionUser.getUser.getUid)) + .and(WORKFLOW_USER_ACCESS.UID.notEqual(workflowOfUserDao.fetchByWid(wid).get(0).getUid)) ) .fetchInto(classOf[AccessEntry]) } @@ -144,12 +136,8 @@ class WorkflowAccessResource() { def grantAccess( @PathParam("wid") wid: UInteger, @PathParam("email") email: String, - @PathParam("privilege") privilege: String, - @Auth user: SessionUser + @PathParam("privilege") privilege: String ): Unit = { - if (!hasWriteAccess(wid, user.getUid)) { - throw new ForbiddenException("No sufficient access privilege.") - } workflowUserAccessDao.merge( new WorkflowUserAccess( userDao.fetchOneByEmail(email).getUid, @@ -170,12 +158,8 @@ class WorkflowAccessResource() { @Path("/revoke/{wid}/{email}") def revokeAccess( @PathParam("wid") wid: UInteger, - @PathParam("email") email: String, - @Auth user: SessionUser + @PathParam("email") email: String ): Unit = { - if (!hasWriteAccess(wid, user.getUid)) { - throw new ForbiddenException("No sufficient access privilege.") - } context .delete(WORKFLOW_USER_ACCESS) .where( diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/workflow/WorkflowResource.scala b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/workflow/WorkflowResource.scala index aaf22f4308f..9eea84ea5cf 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/workflow/WorkflowResource.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/workflow/WorkflowResource.scala @@ -18,6 +18,7 @@ import org.jooq.types.UInteger import java.sql.Timestamp import java.text.{ParseException, SimpleDateFormat} +import java.util import java.util.concurrent.TimeUnit import javax.annotation.security.RolesAllowed import javax.ws.rs._ @@ -231,6 +232,7 @@ object WorkflowResource { } @Produces(Array(MediaType.APPLICATION_JSON)) +@RolesAllowed(Array("REGULAR", "ADMIN")) @Path("/workflow") class WorkflowResource { @@ -240,19 +242,13 @@ class WorkflowResource { * @return WorkflowID[] */ @GET - @Path("/workflow-ids") - @RolesAllowed(Array("REGULAR", "ADMIN")) - def retrieveIDs(@Auth sessionUser: SessionUser): List[String] = { - val user = sessionUser.getUser - val workflowEntries = context + @Path("/user-workflow-ids") + def retrieveIDs(@Auth user: SessionUser): util.List[String] = { + context .select(WORKFLOW_USER_ACCESS.WID) .from(WORKFLOW_USER_ACCESS) .where(WORKFLOW_USER_ACCESS.UID.eq(user.getUid)) - .fetch() - - workflowEntries - .map(workflowRecord => workflowRecord.into(WORKFLOW_OF_USER).getWid.intValue().toString) - .toList + .fetchInto(classOf[String]) } /** @@ -261,24 +257,17 @@ class WorkflowResource { * @return OwnerName[] */ @GET - @Path("/owners") - @RolesAllowed(Array("REGULAR", "ADMIN")) - def retrieveOwners(@Auth sessionUser: SessionUser): List[String] = { - val user = sessionUser.getUser - val workflowEntries = context - .select(USER.EMAIL) + @Path("/user-workflow-owners") + def retrieveOwners(@Auth user: SessionUser): util.List[String] = { + context + .selectDistinct(USER.EMAIL) .from(WORKFLOW_USER_ACCESS) .join(WORKFLOW_OF_USER) .on(WORKFLOW_USER_ACCESS.WID.eq(WORKFLOW_OF_USER.WID)) .join(USER) .on(WORKFLOW_OF_USER.UID.eq(USER.UID)) .where(WORKFLOW_USER_ACCESS.UID.eq(user.getUid)) - .groupBy(USER.UID) - .fetch() - - workflowEntries - .map(workflowRecord => workflowRecord.into(USER).getEmail) - .toList + .fetchInto(classOf[String]) } /** @@ -288,7 +277,6 @@ class WorkflowResource { */ @GET @Path("/search-by-operators") - @RolesAllowed(Array("REGULAR", "ADMIN")) def searchWorkflowByOperator( @QueryParam("operator") operator: String, @Auth sessionUser: SessionUser @@ -340,7 +328,6 @@ class WorkflowResource { */ @GET @Path("/list") - @RolesAllowed(Array("REGULAR", "ADMIN")) def retrieveWorkflowsBySessionUser( @Auth sessionUser: SessionUser ): List[DashboardWorkflow] = { @@ -398,7 +385,6 @@ class WorkflowResource { */ @GET @Path("/{wid}") - @RolesAllowed(Array("REGULAR", "ADMIN")) def retrieveWorkflow( @PathParam("wid") wid: UInteger, @Auth sessionUser: SessionUser @@ -423,7 +409,6 @@ class WorkflowResource { @POST @Consumes(Array(MediaType.APPLICATION_JSON)) @Path("/persist") - @RolesAllowed(Array("REGULAR", "ADMIN")) def persistWorkflow(workflow: Workflow, @Auth sessionUser: SessionUser): Workflow = { val user = sessionUser.getUser @@ -458,7 +443,6 @@ class WorkflowResource { @POST @Consumes(Array(MediaType.APPLICATION_JSON)) @Path("/duplicate") - @RolesAllowed(Array("REGULAR", "ADMIN")) def duplicateWorkflow( workflow: Workflow, @Auth sessionUser: SessionUser @@ -497,7 +481,6 @@ class WorkflowResource { @Consumes(Array(MediaType.APPLICATION_JSON)) @Produces(Array(MediaType.APPLICATION_JSON)) @Path("/create") - @RolesAllowed(Array("REGULAR", "ADMIN")) def createWorkflow(workflow: Workflow, @Auth sessionUser: SessionUser): DashboardWorkflow = { val user = sessionUser.getUser if (workflow.getWid != null) { @@ -523,7 +506,6 @@ class WorkflowResource { */ @DELETE @Path("/{wid}") - @RolesAllowed(Array("REGULAR", "ADMIN")) def deleteWorkflow(@PathParam("wid") wid: UInteger, @Auth sessionUser: SessionUser): Unit = { val user = sessionUser.getUser if (workflowOfUserExists(wid, user.getUid)) { @@ -542,7 +524,6 @@ class WorkflowResource { @Consumes(Array(MediaType.APPLICATION_JSON)) @Produces(Array(MediaType.APPLICATION_JSON)) @Path("/update/name") - @RolesAllowed(Array("REGULAR", "ADMIN")) def updateWorkflowName( workflow: Workflow, @Auth sessionUser: SessionUser diff --git a/core/new-gui/src/app/common/service/workflow-persist/workflow-persist.service.ts b/core/new-gui/src/app/common/service/workflow-persist/workflow-persist.service.ts index be759355019..db592086e5b 100644 --- a/core/new-gui/src/app/common/service/workflow-persist/workflow-persist.service.ts +++ b/core/new-gui/src/app/common/service/workflow-persist/workflow-persist.service.ts @@ -17,9 +17,8 @@ export const WORKFLOW_CREATE_URL = WORKFLOW_BASE_URL + "/create"; export const WORKFLOW_DUPLICATE_URL = WORKFLOW_BASE_URL + "/duplicate"; export const WORKFLOW_UPDATENAME_URL = WORKFLOW_BASE_URL + "/update/name"; export const WORKFLOW_UPDATEDESCRIPTION_URL = WORKFLOW_BASE_URL + "/update/description"; -export const WORKFLOW_OPERATOR_URL = WORKFLOW_BASE_URL + "/search-by-operators"; -export const WORKFLOW_OWNER_URL = WORKFLOW_BASE_URL + "/owners"; -export const WORKFLOW_ID_URL = WORKFLOW_BASE_URL + "/workflow-ids"; +export const WORKFLOW_OWNER_URL = WORKFLOW_BASE_URL + "/user-workflow-owners"; +export const WORKFLOW_ID_URL = WORKFLOW_BASE_URL + "/user-workflow-ids"; export const DEFAULT_WORKFLOW_NAME = "Untitled workflow"; diff --git a/core/new-gui/src/app/dashboard/user/component/share-access/share-access.component.html b/core/new-gui/src/app/dashboard/user/component/share-access/share-access.component.html index fd14daa6d61..8c07d011cc0 100644 --- a/core/new-gui/src/app/dashboard/user/component/share-access/share-access.component.html +++ b/core/new-gui/src/app/dashboard/user/component/share-access/share-access.component.html @@ -60,6 +60,7 @@