/// <summary> Get the link sharing key for a project if it exists, otherwise create a new one. </summary> public async Task <string> GetLinkSharingKeyAsync(string projectId, string role) { SFProject project = await GetProjectAsync(projectId); if (!(project.CheckingConfig.ShareEnabled && project.CheckingConfig.ShareLevel == CheckingShareLevel.Anyone)) { return(null); } SFProjectSecret projectSecret = await ProjectSecrets.GetAsync(projectId); // Link sharing keys have Email set to null and ExpirationTime set to null. string key = projectSecret.ShareKeys.SingleOrDefault( sk => sk.Email == null && sk.ProjectRole == role)?.Key; if (!string.IsNullOrEmpty(key)) { return(key); } // Generate a new link sharing key for the given role key = _securityService.GenerateKey(); await ProjectSecrets.UpdateAsync(p => p.Id == projectId, update => update.Add(p => p.ShareKeys, new ShareKey { Key = key, ProjectRole = role, ExpirationTime = null } )); return(key); }
/// <summary>Return list of email addresses with outstanding invitations</summary> public async Task <string[]> InvitedUsersAsync(string curUserId, string projectId) { SFProject project = await GetProjectAsync(projectId); if (!IsProjectAdmin(project, curUserId)) { throw new ForbiddenException(); } SFProjectSecret projectSecret = await ProjectSecrets.GetAsync(projectId); return(projectSecret.ShareKeys.Select(sk => sk.Email).ToArray()); }
public async Task <bool> InviteAsync(string curUserId, string projectId, string email) { SFProject project = await GetProjectAsync(projectId); if (await RealtimeService.QuerySnapshots <User>() .AnyAsync(u => project.UserRoles.Keys.Contains(u.Id) && u.Email == email)) { return(false); } SiteOptions siteOptions = SiteOptions.Value; if (!project.CheckingConfig.ShareEnabled && !IsProjectAdmin(project, curUserId)) { throw new ForbiddenException(); } // Invite a specific person. Reuse prior code, if any. SFProjectSecret projectSecret = await ProjectSecrets.UpdateAsync( p => p.Id == projectId && !p.ShareKeys.Any(sk => sk.Email == email), update => update.Add(p => p.ShareKeys, new ShareKey { Email = email, Key = _securityService.GenerateKey() })); if (projectSecret == null) { projectSecret = await ProjectSecrets.GetAsync(projectId); } string key = projectSecret.ShareKeys.Single(sk => sk.Email == email).Key; string url = $"{siteOptions.Origin}projects/{projectId}?sharing=true&shareKey={key}"; string emailSpecificLinkMessage = _localizer[SharedResource.Keys.InviteLinkSharingOff]; User inviter = await RealtimeService.GetSnapshotAsync <User>(curUserId); string subject = _localizer[SharedResource.Keys.InviteSubject, project.Name, siteOptions.Name]; var greeting = $"<p>{_localizer[SharedResource.Keys.InviteGreeting, "<p>", inviter.Name, project.Name, siteOptions.Name, $"<a href=\"{url}\">{url}</a><p>"]}"; var instructions = $"<p>{_localizer[SharedResource.Keys.InviteInstructions, siteOptions.Name, "<b>", "</b>"]}"; var pt = $"<ul><li>{_localizer[SharedResource.Keys.InvitePTOption, "<b>", "</b>", siteOptions.Name]}</li>"; var google = $"<li>{_localizer[SharedResource.Keys.InviteGoogleOption, "<b>", "</b>", siteOptions.Name]}</li>"; var facebook = $"<li>{_localizer[SharedResource.Keys.InviteFacebookOption, "<b>", "</b>", siteOptions.Name]}</li>"; var withemail = $"<li>{_localizer[SharedResource.Keys.InviteEmailOption, siteOptions.Name]}</li></ul></p><p></p>"; var signoff = $"<p>{_localizer[SharedResource.Keys.InviteSignature, "<p>", siteOptions.Name]}</p>"; var emailBody = $"{greeting}{emailSpecificLinkMessage}{instructions}{pt}{google}{facebook}{withemail}{signoff}"; await _emailService.SendEmailAsync(email, subject, emailBody); return(true); }
/// <summary>Return list of email addresses with outstanding invitations</summary> public async Task <IReadOnlyList <InviteeStatus> > InvitedUsersAsync(string curUserId, string projectId) { SFProject project = await GetProjectAsync(projectId); if (!IsProjectAdmin(project, curUserId)) { throw new ForbiddenException(); } SFProjectSecret projectSecret = await ProjectSecrets.GetAsync(projectId); DateTime now = DateTime.UtcNow; return(projectSecret.ShareKeys.Where(s => s.Email != null).Select(sk => new InviteeStatus { Email = sk.Email, Expired = sk.ExpirationTime < now }).ToArray()); }
public async Task <bool> InviteAsync(string curUserId, string projectId, string email, string locale, string role) { SFProject project = await GetProjectAsync(projectId); if (await RealtimeService.QuerySnapshots <User>() .AnyAsync(u => project.UserRoles.Keys.Contains(u.Id) && u.Email == email)) { return(false); } SiteOptions siteOptions = SiteOptions.Value; if (!project.CheckingConfig.ShareEnabled && !IsProjectAdmin(project, curUserId)) { throw new ForbiddenException(); } CultureInfo.CurrentUICulture = new CultureInfo(locale); // Remove the user sharekey if expired await ProjectSecrets.UpdateAsync( p => p.Id == projectId, update => update.RemoveAll(p => p.ShareKeys, sk => sk.Email == email && sk.ExpirationTime < DateTime.UtcNow) ); DateTime expTime = DateTime.UtcNow.AddDays(14); // Invite a specific person. Reuse prior code, if any. SFProjectSecret projectSecret = await ProjectSecrets.UpdateAsync( p => p.Id == projectId && !p.ShareKeys.Any(sk => sk.Email == email), update => update.Add(p => p.ShareKeys, new ShareKey { Email = email, Key = _securityService.GenerateKey(), ExpirationTime = expTime, ProjectRole = role } ) ); if (projectSecret == null) { projectSecret = await ProjectSecrets.GetAsync(projectId); int index = projectSecret.ShareKeys.FindIndex(sk => sk.Email == email); // Renew the expiration time of the valid key await ProjectSecrets.UpdateAsync( p => p.Id == projectId && p.ShareKeys.Any(sk => sk.Email == email), update => update.Set(p => p.ShareKeys[index].ExpirationTime, expTime) ); } string key = projectSecret.ShareKeys.Single(sk => sk.Email == email).Key; string url = $"{siteOptions.Origin}projects/{projectId}?sharing=true&shareKey={key}&locale={locale}"; string linkExpires = _localizer[SharedResource.Keys.InviteLinkExpires]; User inviter = await RealtimeService.GetSnapshotAsync <User>(curUserId); string subject = _localizer[SharedResource.Keys.InviteSubject, project.Name, siteOptions.Name]; var greeting = $"<p>{_localizer[SharedResource.Keys.InviteGreeting, "<p>", inviter.Name, project.Name, siteOptions.Name, $"<a href=\"{url}\">{url}</a><p>"]}"; var instructions = $"<p>{_localizer[SharedResource.Keys.InviteInstructions, siteOptions.Name, "<b>", "</b>"]}"; var pt = $"<ul><li>{_localizer[SharedResource.Keys.InvitePTOption, "<b>", "</b>", siteOptions.Name]}</li>"; var google = $"<li>{_localizer[SharedResource.Keys.InviteGoogleOption, "<b>", "</b>", siteOptions.Name]}</li>"; var facebook = $"<li>{_localizer[SharedResource.Keys.InviteFacebookOption, "<b>", "</b>", siteOptions.Name]}</li>"; var withemail = $"<li>{_localizer[SharedResource.Keys.InviteEmailOption, siteOptions.Name]}</li></ul></p><p></p>"; var signoff = $"<p>{_localizer[SharedResource.Keys.InviteSignature, "<p>", siteOptions.Name]}</p>"; var emailBody = $"{greeting}{linkExpires}{instructions}{pt}{google}{facebook}{withemail}{signoff}"; await _emailService.SendEmailAsync(email, subject, emailBody); return(true); }