Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Coscine
backend
apis
Project
Commits
294714ac
Commit
294714ac
authored
May 10, 2021
by
Petar Hristov
💬
Committed by
Marcel Nellesen
May 10, 2021
Browse files
New: Invitation implementation coscine/issues#1453
New: quota implementation coscine/issues#1425
parent
c57d461d
Changes
5
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
294714ac
...
...
@@ -27,4 +27,4 @@ and then trust the generated certificate ```dotnet dev-certs https --trust```
## Testing the new server
The server ist now available under: https://localhost:6000/ (port may be different!)
\ No newline at end of file
The server ist now available under: https://localhost:6000/ (port may be different!)
src/Project.sln
View file @
294714ac
...
...
@@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.156
MinimumVisualStudioVersion = 10.0.40219.1
Project("{
FAE04EC0-301F-11D3-BF4B-00C04F79EFBC
}") = "Project", "Project\Project.csproj", "{16C4EBA5-BA87-45EC-AE1A-E8569A897959}"
Project("{
9A19103F-16F7-4668-BE54-9A1E7A4F7556
}") = "Project", "Project\Project.csproj", "{16C4EBA5-BA87-45EC-AE1A-E8569A897959}"
EndProject
Project("{
FAE04EC0-301F-11D3-BF4B-00C04F79EFBC
}") = "Project.Tests", "Project.Tests\Project.Tests.csproj", "{EEE96892-A211-44EE-B2B8-11FAB31F2E26}"
Project("{
9A19103F-16F7-4668-BE54-9A1E7A4F7556
}") = "Project.Tests", "Project.Tests\Project.Tests.csproj", "{EEE96892-A211-44EE-B2B8-11FAB31F2E26}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
...
...
src/Project/Controllers/ProjectController.cs
View file @
294714ac
using
Coscine.Action
;
using
Coscine.Action.EventArgs
;
using
Coscine.Action.Utils
;
using
Coscine.Api.Project.ParameterObjects
;
using
Coscine.Api.Project.ReturnObjects
;
using
Coscine.ApiCommons
;
...
...
@@ -15,6 +16,7 @@ using Coscine.ResourceLoader;
using
Microsoft.AspNetCore.Authorization
;
using
Microsoft.AspNetCore.Mvc
;
using
Microsoft.Extensions.Logging
;
using
Newtonsoft.Json.Linq
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
...
...
@@ -39,7 +41,13 @@ namespace Coscine.Api.Project.Controllers
private
readonly
ResourceModel
_resourceModel
;
private
readonly
CoscineLogger
_coscineLogger
;
private
readonly
VisibilityModel
_visibilityModel
;
private
readonly
InvitationModel
_invitationModel
;
private
readonly
RoleModel
_roleModel
;
private
readonly
UserModel
_userModel
;
private
readonly
int
_maxAvailable
=
100
;
private
readonly
string
_userUrlPrefix
=
"https://purl.org/coscine/users"
;
private
readonly
Uri
_orgPrefixUrl
=
new
Uri
(
"http://www.w3.org/ns/org#"
);
private
readonly
RdfStoreConnector
_rdfStoreConnector
;
/// <summary>
/// ProjectController constructor
...
...
@@ -58,6 +66,10 @@ namespace Coscine.Api.Project.Controllers
_projectQuotaModel
=
new
ProjectQuotaModel
();
_coscineLogger
=
new
CoscineLogger
(
logger
);
_visibilityModel
=
new
VisibilityModel
();
_rdfStoreConnector
=
new
RdfStoreConnector
(
Program
.
Configuration
.
GetString
(
"coscine/local/virtuoso/additional/url"
));
_invitationModel
=
new
InvitationModel
();
_roleModel
=
new
RoleModel
();
_userModel
=
new
UserModel
();
}
/// <summary>
...
...
@@ -506,6 +518,11 @@ namespace Coscine.Api.Project.Controllers
_projectQuotaModel
.
Delete
(
projectQuota
);
}
foreach
(
var
invitation
in
_invitationModel
.
GetAllWhere
((
x
)
=>
x
.
Project
==
project
.
Id
))
{
_invitationModel
.
Delete
(
invitation
);
}
_activatedFeaturesModel
.
DeactivateAllFeatures
(
project
);
if
(
propegateAction
)
...
...
@@ -532,7 +549,6 @@ namespace Coscine.Api.Project.Controllers
public
IActionResult
Store
()
{
var
user
=
_authenticator
.
GetUser
();
var
isRWTHMember
=
IsRWTHMember
(
user
);
var
projectObject
=
ObjectFactory
<
ProjectObject
>.
DeserializeFromStream
(
Request
.
Body
);
if
(
projectObject
?.
ParentId
!=
new
Guid
()
...
...
@@ -541,7 +557,7 @@ namespace Coscine.Api.Project.Controllers
return
Unauthorized
(
"User is not allowed to create SubProjects."
);
}
var
project
=
_projectModel
.
StoreFromObject
(
projectObject
,
user
,
isRWTHMember
);
var
project
=
_projectModel
.
StoreFromObject
(
projectObject
,
user
,
_rdfStoreConnector
.
GetQuotaDefault
(
user
.
Id
.
ToString
())
);
if
(
projectObject
.
ParentId
!=
new
Guid
()
// for now, only an owner can add subprojects to projects
...
...
@@ -563,26 +579,199 @@ namespace Coscine.Api.Project.Controllers
}
/// <summary>
///
Checks if the given user is a member of the RWTH
///
List all invitations of a project.
/// </summary>
/// <param name="user">User object</param>
/// <returns>True, if member of RWTH or false, if not a member of RWTH</returns>
private
bool
IsRWTHMember
(
User
user
)
/// <param name="projectId">Project id of the project</param>
/// <returns>List of invitations</returns>
[
HttpGet
(
"[controller]/invitation/list/{projectId}"
)]
public
ActionResult
<
IEnumerable
<
InvitationReturnObject
>>
ListInvitations
(
Guid
projectId
)
{
var
externalIds
=
new
ExternalIdModel
().
GetAllWhere
((
externalId
)
=>
externalId
.
UserId
==
user
.
Id
);
if
(!
externalIds
.
Any
())
var
project
=
_projectModel
.
GetById
(
projectId
);
if
(
project
==
null
)
{
return
false
;
return
NotFound
(
$@"The project ""
{
projectId
}
"" was not found."
);
}
var
user
=
_authenticator
.
GetUser
();
if
(!
_projectModel
.
HasAccess
(
user
,
project
,
UserRoles
.
Owner
))
{
return
Unauthorized
(
$"You are not an owner of the project."
);
}
var
invitations
=
_invitationModel
.
GetAllWhere
(
x
=>
x
.
Project
==
projectId
&&
x
.
Expiration
>
DateTime
.
UtcNow
)
.
Select
(
x
=>
new
InvitationReturnObject
{
Id
=
x
.
Id
,
Expiration
=
x
.
Expiration
,
Issuer
=
x
.
Issuer
,
ProjectId
=
x
.
Project
,
RoleId
=
x
.
Role
,
UserMail
=
x
.
InviteeEmail
});
return
new
ActionResult
<
IEnumerable
<
InvitationReturnObject
>>(
invitations
);
}
/// <summary>
/// Create and send an invitation to specified mail.
/// </summary>
/// <param name="sendInvitationObject">Informations for sending an invitation</param>
/// <returns>NoContent</returns>
[
HttpPost
(
"[controller]/invitation"
)]
public
IActionResult
SendInvitation
(
SendInvitationObject
sendInvitationObject
)
{
var
user
=
_authenticator
.
GetUser
();
if
(!
IsValidEmail
(
sendInvitationObject
.
Mail
))
{
return
BadRequest
(
$@"The email ""
{
sendInvitationObject
.
Mail
}
"" is invalid."
);
}
var
project
=
_projectModel
.
GetById
(
sendInvitationObject
.
Project
);
if
(
project
==
null
)
{
return
NotFound
(
$@"The project ""
{
sendInvitationObject
.
Project
}
"" was not found."
);
}
if
(
_roleModel
.
GetById
(
sendInvitationObject
.
Role
)
==
null
)
{
return
NotFound
(
$@"The role ""
{
sendInvitationObject
.
Role
}
"" was not found."
);
}
if
(!
_projectModel
.
HasAccess
(
user
,
project
,
UserRoles
.
Owner
))
{
return
Unauthorized
(
$"You are not an owner of the project."
);
}
var
invitations
=
_invitationModel
.
GetAllWhere
(
x
=>
x
.
Project
==
sendInvitationObject
.
Project
&&
x
.
InviteeEmail
==
sendInvitationObject
.
Mail
&&
x
.
Expiration
>
DateTime
.
UtcNow
);
if
(
invitations
!=
null
&&
invitations
.
Any
())
{
return
BadRequest
(
"This invitee already has a valid invitation to this project."
);
}
var
token
=
_invitationModel
.
CreateInvitation
(
sendInvitationObject
.
Project
,
user
.
Id
,
sendInvitationObject
.
Role
,
sendInvitationObject
.
Mail
);
var
body
=
new
JObject
{
[
"Args"
]
=
new
JObject
()
{
[
"placeholder"
]
=
new
JObject
()
{
[
"confirmation_link"
]
=
$@"
{
_configuration
.
GetString
(
"coscine/local/api/additional/url"
)}
/invitation?token=
{
token
}
"
}
}
};
NotificationBusUtil
.
Send
(
Program
.
Configuration
,
"user_invitation"
,
NotificationBusUtil
.
GetUserList
(
new
User
{
EmailAddress
=
sendInvitationObject
.
Mail
}),
sendInvitationObject
.
Project
.
ToString
(),
body
);
return
NoContent
();
}
/// <summary>
/// Deletes an invitation.
/// </summary>
/// <param name="invitationId">Id of a invitation</param>
/// <returns>NoContent</returns>
[
HttpDelete
(
"[controller]/invitation/{invitationId}"
)]
public
IActionResult
DeleteInvitation
(
Guid
invitationId
)
{
var
invitation
=
_invitationModel
.
GetById
(
invitationId
);
if
(
invitation
==
null
)
{
return
NotFound
(
"Invitation was not found."
);
}
var
externalIdList
=
new
List
<
string
>();
foreach
(
var
externalId
in
externalIds
)
var
user
=
_authenticator
.
GetUser
();
if
(!
_projectModel
.
HasAccess
(
user
,
_projectModel
.
GetById
(
invitation
.
Project
),
UserRoles
.
Owner
))
{
externalIdList
.
Add
(
externalId
.
ExternalId1
);
return
Unauthorized
(
$"You are not an owner of this project."
);
}
return
new
RdfStoreConnector
(
Program
.
Configuration
.
GetStringAndWait
(
"coscine/local/virtuoso/additional/url"
)).
GetTriples
(
new
Uri
(
"https://ror.org/04xfq0f34"
),
null
,
null
,
1
,
externalIdList
).
Any
();
_invitationModel
.
Delete
(
invitation
);
return
NoContent
();
}
/// <summary>
/// Resolve an invitation for the current user.
/// </summary>
/// <param name="token">Token of a invitation</param>
/// <returns>NoContent</returns>
[
HttpGet
(
"[controller]/invitation/resolve/{token}"
)]
public
IActionResult
ResolveInvitation
(
Guid
token
)
{
var
user
=
_authenticator
.
GetUser
();
var
invitation
=
_invitationModel
.
GetByToken
(
token
);
if
(
invitation
==
null
)
{
return
NotFound
(
"Invitation was not found."
);
}
if
(
invitation
.
Expiration
<
DateTime
.
UtcNow
)
{
return
BadRequest
(
"The invitation has expired"
);
}
var
project
=
_projectModel
.
GetById
(
invitation
.
Project
);
if
(!
_projectModel
.
HasAccess
(
_userModel
.
GetById
(
invitation
.
Issuer
),
project
,
UserRoles
.
Owner
))
{
return
Unauthorized
(
$"The issuer is not an owner of the project."
);
}
if
(
_projectRoleModel
.
GetAllWhere
(
x
=>
x
.
ProjectId
==
invitation
.
Project
&&
x
.
UserId
==
user
.
Id
).
Any
())
{
return
BadRequest
(
$"The invitee is already part of the project."
);
}
var
role
=
_roleModel
.
GetById
(
invitation
.
Role
);
_emitter
.
EmitUserAdd
(
new
UserEventArgs
(
_configuration
)
{
Project
=
project
,
Role
=
role
,
User
=
user
,
});
var
projectRole
=
new
ProjectRole
()
{
RelationId
=
Guid
.
NewGuid
(),
ProjectId
=
invitation
.
Project
,
UserId
=
user
.
Id
,
RoleId
=
invitation
.
Role
};
_projectRoleModel
.
Insert
(
projectRole
);
_invitationModel
.
Delete
(
invitation
);
return
Ok
(
$"User
{
user
.
Id
}
is now
{
role
.
DisplayName
}
of project
{
project
.
Id
}
."
);
}
private
static
bool
IsValidEmail
(
string
email
)
{
try
{
return
new
System
.
Net
.
Mail
.
MailAddress
(
email
).
Address
==
email
;
}
catch
{
return
false
;
}
}
private
void
LogAnalyticsViewHome
(
List
<
string
>
projectIds
)
{
_coscineLogger
.
AnalyticsLog
(
...
...
src/Project/ParameterObjects/SendInvitationObject.cs
0 → 100644
View file @
294714ac
using
System
;
namespace
Coscine.Api.Project.ParameterObjects
{
/// <summary>
/// Parameter object containing the invitation informations.
/// </summary>
public
class
SendInvitationObject
{
/// <summary>
/// Id of the project
/// </summary>
public
Guid
Project
{
get
;
set
;
}
/// <summary>
/// Id of the target role
/// </summary>
public
Guid
Role
{
get
;
set
;
}
/// <summary>
/// Email of the target user
/// </summary>
public
string
Mail
{
get
;
set
;
}
}
}
src/Project/ReturnObjects/InvitationReturnObject.cs
0 → 100644
View file @
294714ac
using
System
;
namespace
Coscine.Api.Project.ReturnObjects
{
/// <summary>
/// Return object for an invitation.
/// </summary>
public
class
InvitationReturnObject
{
/// <summary>
/// The invitation id.
/// </summary>
public
Guid
Id
{
get
;
set
;
}
/// <summary>
/// When the invite will expire.
/// </summary>
public
DateTime
Expiration
{
get
;
set
;
}
/// <summary>
/// Email of the invitee.
/// </summary>
public
string
UserMail
{
get
;
set
;
}
/// <summary>
/// Id of the issuer.
/// </summary>
public
Guid
Issuer
{
get
;
set
;
}
/// <summary>
/// Id of the project.
/// </summary>
public
Guid
ProjectId
{
get
;
set
;
}
/// <summary>
/// Id of the target Role.
/// </summary>
public
Guid
RoleId
{
get
;
set
;
}
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment