From 2375471395a17eb68f733863935a74d8cd7b8328 Mon Sep 17 00:00:00 2001 From: Rob Kooper Date: Sat, 25 Mar 2023 22:58:16 -0500 Subject: [PATCH 01/10] add readonly mode tested with create spaces/datasets/files but might be missing special cases. fixes #405 --- CHANGELOG.md | 1 + app/api/Admin.scala | 37 ++--- app/api/ApiController.scala | 12 +- app/api/Permissions.scala | 1 + app/api/Spaces.scala | 48 ++++--- app/controllers/Spaces.scala | 4 +- app/models/User.scala | 2 +- app/views/admin/users.scala.html | 128 ++++++++++-------- app/views/collectionList.scala.html | 2 + app/views/datasetList.scala.html | 3 + app/views/datasets/filesAndFolders.scala.html | 2 + app/views/files/listitem.scala.html | 2 +- app/views/files/tile.scala.html | 2 +- app/views/main.scala.html | 53 ++++---- app/views/spaces/listSpaces.scala.html | 19 +-- 15 files changed, 176 insertions(+), 140 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a201097e2..2383343ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Unreleased ### Added +- Users can be marked as ReadOnly [#405](https://github.com/clowder-framework/clowder/issues/405) - Added Trash button to delete section [#347](https://github.com/clowder-framework/clowder/issues/347) - Add "when" parameter in a few GET API endpoints to enable pagination [#266](https://github.com/clowder-framework/clowder/issues/266) - Extractors can now specify an extractor_key and an owner (email address) when sending a diff --git a/app/api/Admin.scala b/app/api/Admin.scala index d8c878df0..8024b2283 100644 --- a/app/api/Admin.scala +++ b/app/api/Admin.scala @@ -125,9 +125,9 @@ class Admin @Inject() (userService: UserService, list.foreach(id => userService.findById(UUID(id)) match { case Some(u: ClowderUser) => { - if (u.status == UserStatus.Inactive) { + if (u.status != UserStatus.Active) { userService.update(u.copy(status = UserStatus.Active)) - val subject = s"[${AppConfiguration.getDisplayName}] account activated" + val subject = s"[${AppConfiguration.getDisplayName}] account is now active" val body = views.html.emails.userActivated(u, active = true)(request) util.Mail.sendEmail(subject, request.user, u, body) } @@ -138,9 +138,9 @@ class Admin @Inject() (userService: UserService, list.foreach(id => userService.findById(UUID(id)) match { case Some(u: ClowderUser) => { - if (!(u.status == UserStatus.Inactive)) { + if (u.status != UserStatus.Inactive) { userService.update(u.copy(status = UserStatus.Inactive)) - val subject = s"[${AppConfiguration.getDisplayName}] account deactivated" + val subject = s"[${AppConfiguration.getDisplayName}] account is deactivated" val body = views.html.emails.userActivated(u, active = false)(request) util.Mail.sendEmail(subject, request.user, u, body) } @@ -150,26 +150,27 @@ class Admin @Inject() (userService: UserService, (request.body \ "admin").asOpt[List[String]].foreach(list => list.foreach(id => userService.findById(UUID(id)) match { - case Some(u: ClowderUser) if (u.status == UserStatus.Active) => { - - userService.update(u.copy(status = UserStatus.Admin)) - val subject = s"[${AppConfiguration.getDisplayName}] admin access granted" - val body = views.html.emails.userAdmin(u, admin = true)(request) - util.Mail.sendEmail(subject, request.user, u, body) - + case Some(u: ClowderUser) => { + if (u.status != UserStatus.Admin) { + userService.update(u.copy(status = UserStatus.Admin)) + val subject = s"[${AppConfiguration.getDisplayName}] account is now an admin" + val body = views.html.emails.userActivated(u, active = false)(request) + util.Mail.sendEmail(subject, request.user, u, body) + } } case _ => Logger.error(s"Could not update user with id=${id}") })) - (request.body \ "unadmin").asOpt[List[String]].foreach(list => + (request.body \ "readonly").asOpt[List[String]].foreach(list => list.foreach(id => userService.findById(UUID(id)) match { - case Some(u: ClowderUser) if (u.status == UserStatus.Admin) => { - userService.update(u.copy(status = UserStatus.Active)) - val subject = s"[${AppConfiguration.getDisplayName}] admin access revoked" - val body = views.html.emails.userAdmin(u, admin = false)(request) - util.Mail.sendEmail(subject, request.user, u, body) + case Some(u: ClowderUser) => { + if (u.status != UserStatus.ReadOnly) { + userService.update(u.copy(status = UserStatus.ReadOnly)) + val subject = s"[${AppConfiguration.getDisplayName}] account is now an read-only" + val body = views.html.emails.userActivated(u, active = false)(request) + util.Mail.sendEmail(subject, request.user, u, body) + } } - case _ => Logger.error(s"Could not update user with id=${id}") })) Ok(toJson(Map("status" -> "success"))) diff --git a/app/api/ApiController.scala b/app/api/ApiController.scala index d996b6786..f975720db 100644 --- a/app/api/ApiController.scala +++ b/app/api/ApiController.scala @@ -90,10 +90,14 @@ trait ApiController extends Controller { case Some(u) if (u.status == UserStatus.Inactive) => Future.successful(Unauthorized("Account is not activated")) case Some(u) if u.superAdminMode || Permission.checkPermission(userRequest.user, permission, resourceRef) => block(userRequest) case Some(u) => { - affectedResource match { - case Some(resource) if Permission.checkOwner(u, resource) => block(userRequest) - case _ => Future.successful(Unauthorized("Not authorized")) - } + if(u.status == UserStatus.ReadOnly && !api.Permission.READONLY.contains(permission)) { + Future.successful(Unauthorized("Account is read-only")) + } else { + affectedResource match { + case Some(resource) if Permission.checkOwner(u, resource) => block(userRequest) + case _ => Future.successful(Unauthorized("Not authorized")) + } + } } case None if Permission.checkPermission(userRequest.user, permission, resourceRef) => block(userRequest) case _ => Future.successful(Unauthorized("Not authorized")) diff --git a/app/api/Permissions.scala b/app/api/Permissions.scala index ac902a31d..9d8ad5f12 100644 --- a/app/api/Permissions.scala +++ b/app/api/Permissions.scala @@ -426,6 +426,7 @@ object Permission extends Enumeration { def checkPermission(user: User, permission: Permission, resourceRef: ResourceRef): Boolean = { // check if user is owner, in that case they can do what they want. if (user.superAdminMode) return true + if (user.status == UserStatus.ReadOnly && !READONLY.contains(permission)) return false if (checkOwner(users.findByIdentity(user), resourceRef)) return true resourceRef match { diff --git a/app/api/Spaces.scala b/app/api/Spaces.scala index 8dd34edda..8c84eb03e 100644 --- a/app/api/Spaces.scala +++ b/app/api/Spaces.scala @@ -34,33 +34,37 @@ class Spaces @Inject()(spaces: SpaceService, //TODO- Minimal Space created with Name and description. URLs are not yet put in def createSpace() = AuthenticatedAction(parse.json) { implicit request => Logger.debug("Creating new space") - val nameOpt = (request.body \ "name").asOpt[String] - val descOpt = (request.body \ "description").asOpt[String] - (nameOpt, descOpt) match { - case (Some(name), Some(description)) => { - // TODO: add creator - val userId = request.user.get.id - val c = ProjectSpace(name = name, description = description, created = new Date(), creator = userId, - homePage = List.empty, logoURL = None, bannerURL = None, collectionCount = 0, - datasetCount = 0, fileCount = 0, userCount = 0, spaceBytes = 0, metadata = List.empty) - spaces.insert(c) match { - case Some(id) => { - appConfig.incrementCount('spaces, 1) - events.addObjectEvent(request.user, c.id, c.name, "create_space") - userService.findRoleByName("Admin") match { - case Some(realRole) => { - spaces.addUser(userId, realRole, UUID(id)) - } - case None => Logger.info("No admin role found") + if(request.user.get.status == UserStatus.ReadOnly) { + BadRequest(toJson("User is Read-Only")) + } else { + val nameOpt = (request.body \ "name").asOpt[String] + val descOpt = (request.body \ "description").asOpt[String] + (nameOpt, descOpt) match { + case (Some(name), Some(description)) => { + // TODO: add creator + val userId = request.user.get.id + val c = ProjectSpace(name = name, description = description, created = new Date(), creator = userId, + homePage = List.empty, logoURL = None, bannerURL = None, collectionCount = 0, + datasetCount = 0, fileCount = 0, userCount = 0, spaceBytes = 0, metadata = List.empty) + spaces.insert(c) match { + case Some(id) => { + appConfig.incrementCount('spaces, 1) + events.addObjectEvent(request.user, c.id, c.name, "create_space") + userService.findRoleByName("Admin") match { + case Some(realRole) => { + spaces.addUser(userId, realRole, UUID(id)) + } + case None => Logger.info("No admin role found") + } + Ok(toJson(Map("id" -> id))) } - Ok(toJson(Map("id" -> id))) + case None => Ok(toJson(Map("status" -> "error"))) } - case None => Ok(toJson(Map("status" -> "error"))) - } + } + case (_, _) => BadRequest(toJson("Missing required parameters")) } - case (_, _) => BadRequest(toJson("Missing required parameters")) } } diff --git a/app/controllers/Spaces.scala b/app/controllers/Spaces.scala index 49e724aea..07cdb571e 100644 --- a/app/controllers/Spaces.scala +++ b/app/controllers/Spaces.scala @@ -399,7 +399,7 @@ class Spaces @Inject() (spaces: SpaceService, users: UserService, events: EventS def submit() = AuthenticatedAction { implicit request => implicit val user = request.user user match { - case Some(identity) => { + case Some(identity) if identity.status != UserStatus.ReadOnly => { val userId = request.user.get.id //need to get the submitValue before binding form data, in case of errors we want to trigger different forms request.body.asMultipartFormData.get.dataParts.get("submitValue").headOption match { @@ -483,7 +483,7 @@ class Spaces @Inject() (spaces: SpaceService, users: UserService, events: EventS case None => { BadRequest("Did not get any submit button value.") } } } //some identity - case None => Redirect(routes.Spaces.list()).flashing("error" -> "You are not authorized to create/edit $spaceTitle.") + case _ => Redirect(routes.Spaces.list()).flashing("error" -> "You are not authorized to create/edit $spaceTitle.") } } def followingSpaces(index: Int, limit: Int, mode: String) = PrivateServerAction { implicit request => diff --git a/app/models/User.scala b/app/models/User.scala index 5daae5c46..d07fe8020 100644 --- a/app/models/User.scala +++ b/app/models/User.scala @@ -13,7 +13,7 @@ import play.api.libs.json._ object UserStatus extends Enumeration { type UserStatus = Value - val Inactive, Active, Admin = Value + val Inactive, Active, Admin, ReadOnly = Value } /** diff --git a/app/views/admin/users.scala.html b/app/views/admin/users.scala.html index a5b0ed626..856c36eef 100644 --- a/app/views/admin/users.scala.html +++ b/app/views/admin/users.scala.html @@ -18,32 +18,32 @@ never } } - @if(user.fold("")(_.id.stringify) == u.id.stringify) { - @if(!(u.status==UserStatus.Inactive)) { - + @if(user.fold("")(_.id.stringify) == u.id.stringify || configAdmins.contains(u.email.getOrElse(""))) { + + } + @if(u.status==UserStatus.Inactive) { + } else { - + } - } else { - @if(!(u.status==UserStatus.Inactive)) { - + @if(u.status==UserStatus.Active) { + } else { - + } - } - @if(user.fold("")(_.id.stringify) == u.id.stringify) { - - } else { - @if(configAdmins.contains(u.email.getOrElse(""))) { - + @if(u.status==UserStatus.ReadOnly) { + } else { - @if(u.status==UserStatus.Admin) { - - } else { - - } + } - } + @if(u.status==UserStatus.Admin) { + + } else { + + } + } @@ -66,12 +66,11 @@

- + - - + @@ -95,12 +94,11 @@

FullnameFullname Email Provider Last LoginActiveAdminStatus
- + - - + @@ -124,12 +122,11 @@

FullnameFullname Email Provider Last LoginActiveAdminStatus
- + - - + @@ -140,6 +137,34 @@

+
+ +
+
+

FullnameFullname Email Provider Last LoginActiveAdminStatus
+ + + + + + + + + + + @users.filter(u => u.status==UserStatus.ReadOnly).map(printRow) + +
FullnameEmailProviderLast LoginStatus
+ + + + @@ -151,13 +176,14 @@

$(".active").click(function() { var input = $(this)[0]; var parts = input.id.split("-", 2); - $("#admin-" + parts[1]).prop('disabled', !input.checked); + $("#status-" + parts[1]).prop('disabled', !input.checked); }); - var users = { active: [], inactive: [], admin: [], unadmin: [] }; + var users = { active: [], inactive: [], admin: [], readonly: [] }; function submitUsers() { var sendit = false; + $() $(".active:not(:checked)").each(function() { var input = $(this)[0]; var parts = input.id.split("-", 2); @@ -166,27 +192,13 @@

admin.prop('disabled', true); }); - $("input[type=checkbox]").each(function() { - var input = $(this)[0]; - if (input.getAttribute("data-original") != input.checked.toString()) { + $("select").each(function() { + var select = $(this)[0]; + if (select.getAttribute("data-original") != select.value) { sendit = true; - var parts = input.id.split("-", 2); - if (parts[0] == "admin") { - if (input.checked) { - users.admin.push(parts[1]); - } else { - users.unadmin.push(parts[1]); - } - } else if (parts[0] == "active") { - if (input.checked) { - users.active.push(parts[1]); - } else { - users.inactive.push(parts[1]); - } - } else { - logger.error("Not sure what to do with " + parts[0]); - } - input.setAttribute("data-original", input.checked.toString()); + var parts = select.id.split("-", 2); + users[select.value].push(parts[1]); + select.setAttribute("data-original", select.value); } }); @@ -197,19 +209,19 @@

type: "POST", contentType: "application/json" }).done(function () { - users.active.forEach(function(u) { - $('#active-users').append($('#'+u)) - }); - users.unadmin.forEach(function(u) { - $('#active-users').append($('#'+u)) - }); users.inactive.forEach(function(u) { $('#inactive-users').append($('#'+u)) }); users.admin.forEach(function(u) { $('#admin-users').append($('#'+u)) }); - users = { active: [], inactive: [], admin: [], unadmin: [] }; + users.active.forEach(function(u) { + $('#active-users').append($('#'+u)) + }); + users.readonly.forEach(function(u) { + $('#readonly-users').append($('#'+u)) + }); + users = { active: [], inactive: [], admin: [], readonly: [] }; notify("Users successfully updated.", "success", false, 5000); }).fail(function (jqXHR, textStatus, errorThrown){ console.error("The following error occurred: " + textStatus, errorThrown); diff --git a/app/views/collectionList.scala.html b/app/views/collectionList.scala.html index 809ad8046..b190dbb74 100644 --- a/app/views/collectionList.scala.html +++ b/app/views/collectionList.scala.html @@ -43,6 +43,7 @@

@Html(title.getOrElse("Collections"))

+ @if(user.isDefined && user.get.status != UserStatus.ReadOnly) { @user match { case Some(u) => { @@ -79,6 +80,7 @@

@Html(title.getOrElse("Collections"))

} case _ => {} } + }
diff --git a/app/views/datasets/filesAndFolders.scala.html b/app/views/datasets/filesAndFolders.scala.html index ff1350de1..db863798b 100644 --- a/app/views/datasets/filesAndFolders.scala.html +++ b/app/views/datasets/filesAndFolders.scala.html @@ -90,9 +90,11 @@ *@ '
  •  Mark Visible
  • ' + '
  •  Download
  • ' + + @if(user.get.status != UserStatus.ReadOnly) { '
  •  Submit
  • ' + '
  •  Tag
  • ' + '
  •  Delete
  • ' + + } '
  •  Unmark All
  • ' + '
    ') } else { diff --git a/app/views/files/listitem.scala.html b/app/views/files/listitem.scala.html index 72a05c328..aad3b5163 100644 --- a/app/views/files/listitem.scala.html +++ b/app/views/files/listitem.scala.html @@ -36,7 +36,7 @@

    @file.stats.downloads @if(user.isDefined) { - @if(user.get.id.equals(file.author.id) || Permission.checkPermission(Permission.DeleteFile, ResourceRef(ResourceRef.file, file.id))){ + @if(user.get.status != UserStatus.ReadOnly && (user.get.id.equals(file.author.id) || Permission.checkPermission(Permission.DeleteFile, ResourceRef(ResourceRef.file, file.id)))){

    @file.stats.views @file.stats.downloads @if(user.isDefined) { - @if(user.get.id.equals(file.author.id) || Permission.checkPermission(Permission.DeleteFile, ResourceRef(ResourceRef.file, file.id))){ + @if(user.get.status != UserStatus.ReadOnly && (user.get.id.equals(file.author.id) || Permission.checkPermission(Permission.DeleteFile, ResourceRef(ResourceRef.file, file.id)))){ } else { diff --git a/app/views/main.scala.html b/app/views/main.scala.html index 5bd618415..d804a14d1 100644 --- a/app/views/main.scala.html +++ b/app/views/main.scala.html @@ -129,29 +129,30 @@ @if(user.isDefined) { - + }
  • Download All
  • -
  • - Tag All
  • -
  • - Delete All
  • + @if(user.get.status != UserStatus.ReadOnly) { +
  • + Tag All
  • +
  • + Delete All
  • + }
  • Clear All
  • diff --git a/app/views/spaces/listSpaces.scala.html b/app/views/spaces/listSpaces.scala.html index 1518df0ae..9f62efefb 100644 --- a/app/views/spaces/listSpaces.scala.html +++ b/app/views/spaces/listSpaces.scala.html @@ -33,16 +33,19 @@

    @title

    - @(user, owner) match { - case (Some(u), Some(o)) => { - @if(o.equalsIgnoreCase(u.id.stringify)) { - @Messages("create.title", "") + @if(user.isDefined && user.get.status != UserStatus.ReadOnly) { + @(user, owner) match { + case (Some(u), Some(o)) => { + @if(o.equalsIgnoreCase(u.id.stringify)) { + @Messages("create.title", "") + } } + case (Some(u), _) => { + + @Messages("create.title", "") + } + case (_, _) => {} } - case (Some(u), _) => { - @Messages("create.title", "") - } - case (_,_) => {} }
    } @if(u.status==UserStatus.Inactive) { - + } else { - + } @if(u.status==UserStatus.Active) { diff --git a/app/views/collections/miniList.scala.html b/app/views/collections/miniList.scala.html index 2561298c8..b3c2525f5 100644 --- a/app/views/collections/miniList.scala.html +++ b/app/views/collections/miniList.scala.html @@ -24,7 +24,9 @@
    @if(ownProfile) {
    @Messages("home.empty.message", Messages("collections.title").toLowerCase)
    - + @if(user.get.status != UserStatus.ReadOnly) { + + } } else {
    @Messages("profile.empty.message", Messages("collections.title").toLowerCase)
    } diff --git a/app/views/datasets/miniList.scala.html b/app/views/datasets/miniList.scala.html index 6d90e3b75..a3d97dfe7 100644 --- a/app/views/datasets/miniList.scala.html +++ b/app/views/datasets/miniList.scala.html @@ -27,7 +27,9 @@
    @if(ownProfile) {
    @Messages("home.empty.message", Messages("datasets.title").toLowerCase)
    - + @if(user.get.status != UserStatus.ReadOnly) { + + } } else {
    @Messages("profile.empty.message", Messages("datasets.title").toLowerCase)
    } diff --git a/app/views/home.scala.html b/app/views/home.scala.html index f6b58bb28..e45e4b2b1 100644 --- a/app/views/home.scala.html +++ b/app/views/home.scala.html @@ -23,12 +23,14 @@

    @profile.fullName

    diff --git a/app/views/main.scala.html b/app/views/main.scala.html index d804a14d1..268e76992 100644 --- a/app/views/main.scala.html +++ b/app/views/main.scala.html @@ -129,7 +129,7 @@ @if(user.isDefined) { - @if(user.get.status != UserStatus.ReadOnly) { + @if(user.get.status != UserStatus.ReadOnly) {
  • Download All
  • - @if(user.get.status != UserStatus.ReadOnly) { + @if(user.get.status != UserStatus.ReadOnly) {
  • Tag All
  • diff --git a/app/views/selected.scala.html b/app/views/selected.scala.html index dbd3e4a55..e534e2f54 100644 --- a/app/views/selected.scala.html +++ b/app/views/selected.scala.html @@ -24,22 +24,26 @@

    Selections

    Download All - - Delete All - - Tag All + @if(user.get.status != UserStatus.ReadOnly) { + + Delete All + + Tag All + } } else { Download All - - Delete All - - Tag All + @if(user.get.status != UserStatus.ReadOnly) { + + Delete All + + Tag All + } } diff --git a/app/views/spaces/miniList.scala.html b/app/views/spaces/miniList.scala.html index 16915aeab..87bd2876e 100644 --- a/app/views/spaces/miniList.scala.html +++ b/app/views/spaces/miniList.scala.html @@ -23,7 +23,9 @@
    @if(ownProfile) {
    @Messages("home.empty.message", Messages("spaces.title").toLowerCase)
    -
    + @if(user.get.status != UserStatus.ReadOnly) { + + } } else {
    @Messages("profile.empty.message", Messages("spaces.title").toLowerCase)
    } From b64e41f41845356fd1d30a19e828d71a84dcdce9 Mon Sep 17 00:00:00 2001 From: Rob Kooper Date: Tue, 11 Apr 2023 17:00:18 -0500 Subject: [PATCH 03/10] send email with correct status --- app/views/emails/userActivated.scala.html | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/views/emails/userActivated.scala.html b/app/views/emails/userActivated.scala.html index 1995e92d0..0e0a7a7e1 100644 --- a/app/views/emails/userActivated.scala.html +++ b/app/views/emails/userActivated.scala.html @@ -7,13 +7,8 @@ @user.fullName,

    - Your account on @AppConfiguration.getDisplayName
    - has been - @if(active) { - enabled and you can now login. - } else { - disabled. - } + Your account on @AppConfiguration.getDisplayName + has been made @user.status.

    @footer() From 1992c50a3a7e0227441b9ef6e6dcb96004453b46 Mon Sep 17 00:00:00 2001 From: Rob Kooper Date: Tue, 11 Apr 2023 19:37:48 -0500 Subject: [PATCH 04/10] allow to download (based on permission) --- app/api/ApiController.scala | 2 +- app/api/Permissions.scala | 2 +- app/controllers/SecuredController.scala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/api/ApiController.scala b/app/api/ApiController.scala index 673621d84..2a5c435b1 100644 --- a/app/api/ApiController.scala +++ b/app/api/ApiController.scala @@ -88,7 +88,7 @@ trait ApiController extends Controller { userRequest.user match { case Some(u) if !AppConfiguration.acceptedTermsOfServices(u.termsOfServices) => Future.successful(Unauthorized("Terms of Service not accepted")) case Some(u) if (u.status == UserStatus.Inactive) => Future.successful(Unauthorized("Account is not activated")) - case Some(u) if (u.status == UserStatus.ReadOnly && !api.Permission.READONLY.contains(permission)) => Future.successful(Unauthorized("Account is ReadOnly")) + case Some(u) if (u.status == UserStatus.ReadOnly && !api.Permission.READONLY.contains(permission) && permission != Permission.DownloadFiles) => Future.successful(Unauthorized("Account is ReadOnly")) case Some(u) if u.superAdminMode || Permission.checkPermission(userRequest.user, permission, resourceRef) => block(userRequest) case Some(u) => { affectedResource match { diff --git a/app/api/Permissions.scala b/app/api/Permissions.scala index 9d8ad5f12..e3c6ca5c3 100644 --- a/app/api/Permissions.scala +++ b/app/api/Permissions.scala @@ -426,7 +426,7 @@ object Permission extends Enumeration { def checkPermission(user: User, permission: Permission, resourceRef: ResourceRef): Boolean = { // check if user is owner, in that case they can do what they want. if (user.superAdminMode) return true - if (user.status == UserStatus.ReadOnly && !READONLY.contains(permission)) return false + if (user.status == UserStatus.ReadOnly && !READONLY.contains(permission) && permission != Permission.DownloadFiles) return false if (checkOwner(users.findByIdentity(user), resourceRef)) return true resourceRef match { diff --git a/app/controllers/SecuredController.scala b/app/controllers/SecuredController.scala index d467db4a0..ce4dae8c6 100644 --- a/app/controllers/SecuredController.scala +++ b/app/controllers/SecuredController.scala @@ -104,7 +104,7 @@ trait SecuredController extends Controller { userRequest.user match { case Some(u) if !AppConfiguration.acceptedTermsOfServices(u.termsOfServices) => Future.successful(Results.Redirect(routes.Application.tos(Some(request.uri)))) case Some(u) if (u.status==UserStatus.Inactive) => Future.successful(Results.Redirect(routes.Error.notActivated())) - case Some(u) if (u.status==UserStatus.ReadOnly && !api.Permission.READONLY.contains(permission)) => { + case Some(u) if (u.status==UserStatus.ReadOnly && !api.Permission.READONLY.contains(permission) && permission != Permission.DownloadFiles) => { Future.successful(Results.Redirect(routes.Error.notAuthorized("Account is ReadOnly", "", ""))) } case Some(u) if u.superAdminMode || Permission.checkPermission(userRequest.user, permission, resourceRef) => block(userRequest) From b38a8c1c56efdb4a1f9594c21af239561af09e39 Mon Sep 17 00:00:00 2001 From: Rob Kooper Date: Tue, 11 Apr 2023 20:05:19 -0500 Subject: [PATCH 05/10] fix user status email --- app/api/Admin.scala | 8 ++++---- app/views/emails/userAdmin.scala.html | 14 -------------- ...Activated.scala.html => userChanged.scala.html} | 4 ++-- 3 files changed, 6 insertions(+), 20 deletions(-) delete mode 100644 app/views/emails/userAdmin.scala.html rename app/views/emails/{userActivated.scala.html => userChanged.scala.html} (71%) diff --git a/app/api/Admin.scala b/app/api/Admin.scala index 8024b2283..27bc8f482 100644 --- a/app/api/Admin.scala +++ b/app/api/Admin.scala @@ -128,7 +128,7 @@ class Admin @Inject() (userService: UserService, if (u.status != UserStatus.Active) { userService.update(u.copy(status = UserStatus.Active)) val subject = s"[${AppConfiguration.getDisplayName}] account is now active" - val body = views.html.emails.userActivated(u, active = true)(request) + val body = views.html.emails.userChanged(u, "activated")(request) util.Mail.sendEmail(subject, request.user, u, body) } } @@ -141,7 +141,7 @@ class Admin @Inject() (userService: UserService, if (u.status != UserStatus.Inactive) { userService.update(u.copy(status = UserStatus.Inactive)) val subject = s"[${AppConfiguration.getDisplayName}] account is deactivated" - val body = views.html.emails.userActivated(u, active = false)(request) + val body = views.html.emails.userChanged(u, "deactivated")(request) util.Mail.sendEmail(subject, request.user, u, body) } } @@ -154,7 +154,7 @@ class Admin @Inject() (userService: UserService, if (u.status != UserStatus.Admin) { userService.update(u.copy(status = UserStatus.Admin)) val subject = s"[${AppConfiguration.getDisplayName}] account is now an admin" - val body = views.html.emails.userActivated(u, active = false)(request) + val body = views.html.emails.userChanged(u, "an admin account")(request) util.Mail.sendEmail(subject, request.user, u, body) } } @@ -167,7 +167,7 @@ class Admin @Inject() (userService: UserService, if (u.status != UserStatus.ReadOnly) { userService.update(u.copy(status = UserStatus.ReadOnly)) val subject = s"[${AppConfiguration.getDisplayName}] account is now an read-only" - val body = views.html.emails.userActivated(u, active = false)(request) + val body = views.html.emails.userChanged(u, "read-only")(request) util.Mail.sendEmail(subject, request.user, u, body) } } diff --git a/app/views/emails/userAdmin.scala.html b/app/views/emails/userAdmin.scala.html deleted file mode 100644 index 9ebcbc651..000000000 --- a/app/views/emails/userAdmin.scala.html +++ /dev/null @@ -1,14 +0,0 @@ -@(user: User, admin: Boolean, ssl: Boolean = true)(implicit request: RequestHeader) - -@import services.AppConfiguration - - - -

    @user.fullName,

    -

    - Your account on @AppConfiguration.getDisplayName - now @if(!admin) { no longer } has admin privileges. -

    - @footer() - - diff --git a/app/views/emails/userActivated.scala.html b/app/views/emails/userChanged.scala.html similarity index 71% rename from app/views/emails/userActivated.scala.html rename to app/views/emails/userChanged.scala.html index 0e0a7a7e1..9630f0305 100644 --- a/app/views/emails/userActivated.scala.html +++ b/app/views/emails/userChanged.scala.html @@ -1,4 +1,4 @@ -@(user: User, active: Boolean, ssl: Boolean = true)(implicit request: RequestHeader) +@(user: User, statis: String, ssl: Boolean = true)(implicit request: RequestHeader) @import services.AppConfiguration @@ -8,7 +8,7 @@

    Your account on @AppConfiguration.getDisplayName - has been made @user.status. + has been made @status.

    @footer() From 905fa84a617b3f521d9fa7439407b42a39594b06 Mon Sep 17 00:00:00 2001 From: Rob Kooper Date: Tue, 11 Apr 2023 22:14:11 -0500 Subject: [PATCH 06/10] typo --- app/views/emails/userChanged.scala.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/emails/userChanged.scala.html b/app/views/emails/userChanged.scala.html index 9630f0305..09c9dce91 100644 --- a/app/views/emails/userChanged.scala.html +++ b/app/views/emails/userChanged.scala.html @@ -1,4 +1,4 @@ -@(user: User, statis: String, ssl: Boolean = true)(implicit request: RequestHeader) +@(user: User, status: String, ssl: Boolean = true)(implicit request: RequestHeader) @import services.AppConfiguration From 307928898d6fed949b517610cc61d54cc50cd05f Mon Sep 17 00:00:00 2001 From: Rob Kooper Date: Fri, 14 Apr 2023 17:17:51 -0500 Subject: [PATCH 07/10] fix page for user change --- app/views/admin/users.scala.html | 33 +++++++++----------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/app/views/admin/users.scala.html b/app/views/admin/users.scala.html index 1750114b7..046a47c1a 100644 --- a/app/views/admin/users.scala.html +++ b/app/views/admin/users.scala.html @@ -24,24 +24,24 @@ @@ -173,31 +173,16 @@