Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,14 @@ export class ProjectMemberPipe implements PipeTransform {
return projectUsers.filter(x => {
return x.userRole == "member"
})
case "allMembers":
return projectUsers.filter(x => {
return x.userRole == "owner" || x.userRole == "admin" || x.userRole == "member"
})
default:
return projectUsers.filter(x => {
return x.userRole == "member" || x.userRole == "admin"
})
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
<li class="nav-item dropdown notification-nav-item">
<a
class="nav-link nav-interactive notification-trigger"
[class.has-unread-notifications]="((unreadCount$ | async) || 0) > 0"
href="#"
id="navbarNotificationMenuLink"
aria-haspopup="true"
Expand Down
12 changes: 10 additions & 2 deletions src/Analysim.Web/ClientApp/src/app/navbar/navbar.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@
border-radius: var(--nav-link-radius);
}

.notification-trigger.has-unread-notifications {
background: var(--c-danger-background);
}

.notification-trigger.has-unread-notifications .fa-bell {
color: color-mix(in srgb, var(--color-danger) 65%, var(--c-text-inverse));
}

.notification-badge {
position: absolute;
top: 3px;
Expand All @@ -106,9 +114,9 @@
height: 17px;
padding: 0 4px;
border-radius: 999px;
background: #d94a38;
background: var(--color-danger);
color: #fff;
border: 1px solid var(--background-color-tertiary);
border: 1px solid var(--background-color-secondary);
font-size: 10px;
font-weight: 700;
line-height: 15px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ <h5 class="modal-title">Member List</h5>
<ul class="project-authors-list">
<li
class="project-author"
*ngFor="let member of projectUsers | projectMember: 'owner'"
*ngFor="let member of projectUsers | projectMember: 'allMembers'"
[routerLink]="['/profile/' + member.user.userName]"
(click)="closeModal()"
>
Expand Down
128 changes: 75 additions & 53 deletions src/Analysim.Web/Controllers/ProjectController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,17 @@ public async Task<IActionResult> AddProjectLog([FromForm] CreateProjectLogVM for
var project = await _dbContext.Projects.FindAsync(formdata.ProjectID);
if (project == null) return NotFound(new { message = "Project Not Found." });

bool hasProjectLogAccess = await _dbContext.ProjectUsers
.AnyAsync(aup =>
aup.UserID == user.Id &&
aup.ProjectID == project.ProjectID &&
(aup.UserRole == "owner" || aup.UserRole == "member"));

if (!hasProjectLogAccess)
{
return StatusCode(StatusCodes.Status403Forbidden, new { message = "You must be an owner or member of the project" });
}

// Validate Content
if (string.IsNullOrWhiteSpace(formdata.Content))
{
Expand Down Expand Up @@ -2065,17 +2076,6 @@ public async Task<IActionResult> FollowProject([FromRoute] int projectID)
_dbContext.Entry(projectUser).State = EntityState.Modified;
await _dbContext.SaveChangesAsync();

try
{
await _notificationService.PublishAsync(new NotificationEvent
{
Type = NotificationTypes.ProjectJoined,
ActorUserID = user.Id,
ProjectID = project.ProjectID
});
}
catch (Exception) { }

return Ok(new
{
result = projectUser,
Expand All @@ -2097,17 +2097,6 @@ await _notificationService.PublishAsync(new NotificationEvent
_dbContext.Entry(projectUser).Reference(pu => pu.User).Load();
_dbContext.Entry(projectUser).Reference(pu => pu.Project).Load();

try
{
await _notificationService.PublishAsync(new NotificationEvent
{
Type = NotificationTypes.ProjectJoined,
ActorUserID = user.Id,
ProjectID = project.ProjectID
});
}
catch (Exception) { }

return Ok(new
{
result = projectUser,
Expand Down Expand Up @@ -2332,6 +2321,21 @@ public async Task<IActionResult> RequestJoinProject([FromRoute] int projectID)
joinRequest = await ProjectMembershipRequestsWithUsers()
.SingleAsync(pmr => pmr.ProjectMembershipRequestID == joinRequest.ProjectMembershipRequestID);

try
{
await _notificationService.PublishAsync(new NotificationEvent
{
Type = NotificationTypes.ProjectJoined,
ActorUserID = user.Id,
ProjectID = project.ProjectID,
Data = new Dictionary<string, string>
{
["membershipRequestID"] = joinRequest.ProjectMembershipRequestID.ToString()
}
});
}
catch (Exception) { }

return Ok(new
{
result = joinRequest,
Expand Down Expand Up @@ -2771,13 +2775,16 @@ public async Task<IActionResult> UploadFile([FromForm] ProjectFileUploadVM formd
var user = await _dbContext.Users.SingleOrDefaultAsync(u => u.Id == userId);
if (user == null) return NotFound(new { message = "User Not Found" });

bool isOwner = await _dbContext.Projects
bool hasUploadAccess = await _dbContext.Projects
.AnyAsync(p => p.ProjectUsers.Any(aup =>
aup.User.Id == user.Id &&
aup.Project.ProjectID == formdata.ProjectID &&
aup.UserRole == "owner"));
aup.UserID == user.Id &&
aup.ProjectID == formdata.ProjectID &&
(aup.UserRole == "owner" || aup.UserRole == "member")));

if (!isOwner) return Unauthorized(new { message = "You are not the owner of the project" });
if (!hasUploadAccess)
{
return StatusCode(StatusCodes.Status403Forbidden, new { message = "You must be an owner or member of the project" });
}


if (formdata.Directory == null) { formdata.Directory = ""; }
Expand Down Expand Up @@ -2887,13 +2894,16 @@ public async Task<IActionResult> UploadNotebook([FromForm] ProjectNotebookUpload
if (user == null) return NotFound(new { message = "User Not Found" });


bool isOwner = await _dbContext.Projects
bool hasNotebookUploadAccess = await _dbContext.Projects
.AnyAsync(p => p.ProjectUsers.Any(aup =>
aup.User.Id == user.Id &&
aup.Project.ProjectID == noteBookData.ProjectID &&
aup.UserRole == "owner"));
aup.UserID == user.Id &&
aup.ProjectID == noteBookData.ProjectID &&
(aup.UserRole == "owner" || aup.UserRole == "member")));

if (!isOwner) return Unauthorized(new { message = "You are not the owner of the project" });
if (!hasNotebookUploadAccess)
{
return StatusCode(StatusCodes.Status403Forbidden, new { message = "You must be an owner or member of the project" });
}


// Find Project
Expand Down Expand Up @@ -2984,12 +2994,15 @@ public async Task<IActionResult> UploadNotebookNewVersion([FromForm] ProjectNote
var user = await _dbContext.Users.SingleOrDefaultAsync(u => u.Id == userId);
if (user == null) return NotFound(new { message = "User Not Found" });

bool isOwner = await _dbContext.Projects
bool hasNotebookUploadAccess = await _dbContext.Projects
.AnyAsync(p => p.ProjectUsers.Any(aup =>
aup.User.Id == user.Id &&
aup.Project.ProjectID == noteBookData.ProjectID &&
aup.UserRole == "owner"));
if (!isOwner) return Unauthorized(new { message = "You are not the owner of the project" });
aup.UserID == user.Id &&
aup.ProjectID == noteBookData.ProjectID &&
(aup.UserRole == "owner" || aup.UserRole == "member")));
if (!hasNotebookUploadAccess)
{
return StatusCode(StatusCodes.Status403Forbidden, new { message = "You must be an owner or member of the project" });
}


// Find Project
Expand Down Expand Up @@ -3067,13 +3080,16 @@ public async Task<IActionResult> UploadExistingNotebook([FromForm] ExistingProje
var user = await _dbContext.Users.SingleOrDefaultAsync(u => u.Id == userId);
if (user == null) return NotFound(new { message = "User Not Found" });

bool isOwner = await _dbContext.Projects
bool hasNotebookUploadAccess = await _dbContext.Projects
.AnyAsync(p => p.ProjectUsers.Any(aup =>
aup.User.Id == user.Id &&
aup.Project.ProjectID == noteBookData.ProjectID &&
aup.UserRole == "owner"));
aup.UserID == user.Id &&
aup.ProjectID == noteBookData.ProjectID &&
(aup.UserRole == "owner" || aup.UserRole == "member")));

if (!isOwner) return Unauthorized(new { message = "You are not the owner of the project" });
if (!hasNotebookUploadAccess)
{
return StatusCode(StatusCodes.Status403Forbidden, new { message = "You must be an owner or member of the project" });
}


var project = await _dbContext.Projects.FindAsync(noteBookData.ProjectID);
Expand Down Expand Up @@ -3204,13 +3220,16 @@ public async Task<IActionResult> CreateFolder([FromForm] FolderUploadProfileView
var user = await _dbContext.Users.SingleOrDefaultAsync(u => u.Id == userId);
if (user == null) return NotFound(new { message = "User Not Found" });

bool isOwner = await _dbContext.Projects
bool hasFolderAccess = await _dbContext.Projects
.AnyAsync(p => p.ProjectUsers.Any(aup =>
aup.User.Id == user.Id &&
aup.Project.ProjectID == formdata.ProjectID &&
aup.UserRole == "owner"));
aup.UserID == user.Id &&
aup.ProjectID == formdata.ProjectID &&
(aup.UserRole == "owner" || aup.UserRole == "member")));

if (!isOwner) return Unauthorized(new { message = "You are not the owner of the project" });
if (!hasFolderAccess)
{
return StatusCode(StatusCodes.Status403Forbidden, new { message = "You must be an owner or member of the project" });
}


if (formdata.Directory == null) { formdata.Directory = ""; }
Expand All @@ -3234,7 +3253,7 @@ public async Task<IActionResult> CreateFolder([FromForm] FolderUploadProfileView
Uri = "",
DateCreated = DateTimeOffset.UtcNow,
LastModified = DateTimeOffset.UtcNow,
UserID = formdata.UserID,
UserID = user.Id,
ProjectID = formdata.ProjectID
};

Expand Down Expand Up @@ -3276,13 +3295,16 @@ public async Task<IActionResult> CreateNotebookFolder([FromForm] FolderUploadPro
var user = await _dbContext.Users.SingleOrDefaultAsync(u => u.Id == userId);
if (user == null) return NotFound(new { message = "User Not Found" });

bool isOwner = await _dbContext.Projects
bool hasFolderAccess = await _dbContext.Projects
.AnyAsync(p => p.ProjectUsers.Any(aup =>
aup.User.Id == user.Id &&
aup.Project.ProjectID == formdata.ProjectID &&
aup.UserRole == "owner"));
aup.UserID == user.Id &&
aup.ProjectID == formdata.ProjectID &&
(aup.UserRole == "owner" || aup.UserRole == "member")));

if (!isOwner) return Unauthorized(new { message = "You are not the owner of the project" });
if (!hasFolderAccess)
{
return StatusCode(StatusCodes.Status403Forbidden, new { message = "You must be an owner or member of the project" });
}


if (formdata.Directory == null) { formdata.Directory = ""; }
Expand Down
6 changes: 3 additions & 3 deletions src/Analysim.Web/Services/NotificationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,9 @@ private async Task PublishProjectJoinedAsync(NotificationEvent notificationEvent

var actorName = await GetUserDisplayNameAsync(notificationEvent.ActorUserID, "Someone");
var projectName = GetProjectName(project);
var link = BuildProjectLink(project, null);
var title = "Someone joined your project";
var body = $"{actorName} joined {projectName}.";
var link = BuildProjectLink(project, "edit");
var title = "Someone requested to join your project";
var body = $"{actorName} requested to join {projectName}.";

await CreateAndSendAsync(
notificationEvent,
Expand Down
Loading