Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • Fix/xxxx-activateGitlab
  • Fix/xxxx-resourceVisibility
  • Hotfix/1262-fixStatuscode
  • Hotfix/1308-versionConflict
  • Hotfix/1357-ymlFile
  • Hotfix/1370-swaggerDescription
  • Hotfix/1383-topLevel
  • Hotfix/1433-defaultQuota
  • Hotfix/1466-projectCreationTimeout
  • Hotfix/1584-fixResourceLoader
  • Hotfix/1590-quotaFix
  • Hotfix/1615-membersCreatingProject
  • Hotfix/1668-versionResourceConfigDepVersion
  • Hotfix/1669-RDS-S3QuotaManagement
  • Hotfix/1704-FixingArchiveFlag
  • Hotfix/1796-projectDdos
  • Hotfix/1917-PublicFilesVisibility
  • Hotfix/2015-PublicFilesVisibility
  • Hotfix/2077-fixSupportAdminLog
  • Hotfix/2087-efNet6
  • Hotfix/2202-fixNaNQuota
  • Hotfix/2203-quotaMembersFix
  • Hotfix/2224-quotaSizeAnalytics
  • Hotfix/2371-fixGitLabinRCV
  • Hotfix/64-releaseUDE
  • Issue/1321-pidEnquiryOverhaul
  • Issue/1825-codeQualityPipelines
  • Issue/1825-codeQualityPipelinesNew
  • Issue/1860-searchScoping
  • Issue/1861-searchMetadata
  • Issue/1866-ExtendResourceTypeConfigurationTUDo
  • Issue/1877-ExtendResourceTypeConfigurationNRWFHs
  • Issue/1910-MigrationtoNET6.0
  • Issue/1927-projectAppMigration
  • Issue/1940ResouceKeysForNRWAndTUDO
  • Issue/1951-quotaImplementation
  • Issue/1957-resourceAppMigrationNew
  • Issue/1971-projectEditCreateMigration
  • Issue/1971-projectForDev
  • Issue/2000-gitlabResourcesAPI
  • Issue/2001-extendAnalyticsLogger
  • Issue/2008-quotaManagement
  • Issue/2061-activateResourceTypeRdss3nrw
  • Issue/2072-wormResourceType
  • Issue/2101-gitLabResTypeUi
  • Issue/2221-projectDateCreated
  • Issue/2246-quotaResoval
  • Issue/2259-updatePids
  • Issue/2287-guestRole
  • Issue/2309-docs
  • Issue/2328-noFailOnLog
  • Issue/2349-gitlabHttps
  • Issue/2355-topLevelOrg
  • Issue/2449-GuidPidSlugToProjectSettings
  • Issues/0028-maxQuotaFix
  • Product/1100-fdsS3
  • Product/1154-resourceTypeDefinition
  • Product/1188-LoggingExtended
  • Product/1215-gitlabCleanUp
  • Product/1287-dotnet5Sharepoint
  • Product/1414-fhPrivileges
  • Product/1442-projectInviteMngmnt
  • Product/1548-projectInviteMngmnt
  • Product/1600-rdsS3QuotaManagement
  • Product/1629-onboardingOtherUniversities
  • Product/202-userInvitation
  • Product/588-quotaManagement
  • Product/932-docuProjectApi
  • Sprint/2020-20
  • Sprint/2020-21
  • Sprint/2020-22
  • Sprint/2021-01
  • Sprint/2021-02
  • Sprint/2021-03
  • Sprint/2021-05
  • Sprint/2021-08
  • Sprint/2021-09
  • Sprint/2021-10
  • Sprint/2021-11
  • Sprint/2021-12
  • Sprint/2021-13
  • Sprint/2021-15
  • Sprint/2021-19
  • Sprint/2021-2022
  • Sprint/2021-23
  • Sprint/2022-01
  • Sprint/2022-05
  • Test/xxxx-enablingGitLab
  • Topic/1115-docuProjectApi
  • Topic/1159-rtdApi
  • Topic/1221-LogginExtendedNew
  • Topic/1221-LoggingExtended
  • Topic/1279-quotaManagement
  • Topic/1292-FdsS3
  • Topic/1335-dotnet5Apis
  • Topic/1425-fhPrivileges
  • Topic/1453-userInvitation
  • Topic/1529-HandleExternalUserInvitation
  • Topic/1530-invitationUserManagement
  • Topic/1531-UseMangmntTableView
  • v1.0.0
  • v1.1.0
  • v1.10.0
  • v1.11.0
  • v1.11.1
  • v1.12.0
  • v1.13.0
  • v1.13.1
  • v1.14.0
  • v1.15.0
  • v1.15.1
  • v1.16.0
  • v1.16.1
  • v1.17.0
  • v1.17.1
  • v1.18.0
  • v1.19.0
  • v1.2.0
  • v1.2.1
  • v1.20.0
  • v1.20.1
  • v1.20.2
  • v1.21.0
  • v1.21.1
  • v1.22.0
  • v1.23.0
  • v1.23.1
  • v1.23.2
  • v1.23.3
  • v1.24.0
  • v1.24.1
  • v1.25.0
  • v1.25.1
  • v1.3.0
  • v1.4.0
  • v1.4.1
  • v1.5.0
  • v1.5.1
  • v1.6.0
  • v1.6.1
  • v1.6.2
  • v1.7.0
  • v1.7.1
  • v1.8.0
  • v1.9.0
  • v2.0.0
  • v2.0.1
  • v2.0.2
  • v2.1.0
  • v2.1.1
  • v2.1.2
  • v2.2.0
  • v2.2.1
  • v2.2.2
  • v2.2.3
  • v2.2.4
  • v2.2.5
  • v2.3.0
  • v2.4.0
  • v2.4.1
  • v2.4.2
  • v2.4.3
  • v2.5.0
  • v2.5.1
  • v2.5.2
  • v2.5.3
  • v2.5.4
  • v2.6.0
  • v2.6.1
  • v2.6.2
  • v2.7.0
  • v2.8.0
  • v2.8.1
  • v2.8.2
  • v2.8.3
  • v2.8.4
  • v2.9.0
  • v3.0.0
  • v3.0.1
  • v4.0.0
  • v4.0.1
  • v4.0.2
  • v4.0.3
  • v4.1.0
  • v4.1.1
  • v4.2.0
  • v4.2.1
  • v4.2.2
  • v4.2.3
  • v4.2.4
  • v4.2.5
  • v4.2.6
  • v4.2.7
  • v4.2.8
  • v4.3.0
  • v4.3.1
  • v4.3.2
  • v4.3.3
  • v4.3.4
  • v4.4.0
200 results

Target

Select target project
  • coscine/backend/apis/project
1 result
Select Git revision
  • Fix/xxxx-activateGitlab
  • Fix/xxxx-resourceVisibility
  • Hotfix/1262-fixStatuscode
  • Hotfix/1308-versionConflict
  • Hotfix/1357-ymlFile
  • Hotfix/1370-swaggerDescription
  • Hotfix/1383-topLevel
  • Hotfix/1433-defaultQuota
  • Hotfix/1466-projectCreationTimeout
  • Hotfix/1584-fixResourceLoader
  • Hotfix/1590-quotaFix
  • Hotfix/1615-membersCreatingProject
  • Hotfix/1668-versionResourceConfigDepVersion
  • Hotfix/1669-RDS-S3QuotaManagement
  • Hotfix/1704-FixingArchiveFlag
  • Hotfix/1796-projectDdos
  • Hotfix/1917-PublicFilesVisibility
  • Hotfix/2015-PublicFilesVisibility
  • Hotfix/2077-fixSupportAdminLog
  • Hotfix/2087-efNet6
  • Hotfix/2202-fixNaNQuota
  • Hotfix/2203-quotaMembersFix
  • Hotfix/2224-quotaSizeAnalytics
  • Hotfix/2371-fixGitLabinRCV
  • Hotfix/64-releaseUDE
  • Issue/1321-pidEnquiryOverhaul
  • Issue/1825-codeQualityPipelines
  • Issue/1825-codeQualityPipelinesNew
  • Issue/1860-searchScoping
  • Issue/1861-searchMetadata
  • Issue/1866-ExtendResourceTypeConfigurationTUDo
  • Issue/1877-ExtendResourceTypeConfigurationNRWFHs
  • Issue/1910-MigrationtoNET6.0
  • Issue/1927-projectAppMigration
  • Issue/1940ResouceKeysForNRWAndTUDO
  • Issue/1951-quotaImplementation
  • Issue/1957-resourceAppMigrationNew
  • Issue/1971-projectEditCreateMigration
  • Issue/1971-projectForDev
  • Issue/2000-gitlabResourcesAPI
  • Issue/2001-extendAnalyticsLogger
  • Issue/2008-quotaManagement
  • Issue/2061-activateResourceTypeRdss3nrw
  • Issue/2072-wormResourceType
  • Issue/2101-gitLabResTypeUi
  • Issue/2221-projectDateCreated
  • Issue/2246-quotaResoval
  • Issue/2259-updatePids
  • Issue/2287-guestRole
  • Issue/2309-docs
  • Issue/2328-noFailOnLog
  • Issue/2349-gitlabHttps
  • Issue/2355-topLevelOrg
  • Issue/2449-GuidPidSlugToProjectSettings
  • Issues/0028-maxQuotaFix
  • Product/1100-fdsS3
  • Product/1154-resourceTypeDefinition
  • Product/1188-LoggingExtended
  • Product/1215-gitlabCleanUp
  • Product/1287-dotnet5Sharepoint
  • Product/1414-fhPrivileges
  • Product/1442-projectInviteMngmnt
  • Product/1548-projectInviteMngmnt
  • Product/1600-rdsS3QuotaManagement
  • Product/1629-onboardingOtherUniversities
  • Product/202-userInvitation
  • Product/588-quotaManagement
  • Product/932-docuProjectApi
  • Sprint/2020-20
  • Sprint/2020-21
  • Sprint/2020-22
  • Sprint/2021-01
  • Sprint/2021-02
  • Sprint/2021-03
  • Sprint/2021-05
  • Sprint/2021-08
  • Sprint/2021-09
  • Sprint/2021-10
  • Sprint/2021-11
  • Sprint/2021-12
  • Sprint/2021-13
  • Sprint/2021-15
  • Sprint/2021-19
  • Sprint/2021-2022
  • Sprint/2021-23
  • Sprint/2022-01
  • Sprint/2022-05
  • Test/xxxx-enablingGitLab
  • Topic/1115-docuProjectApi
  • Topic/1159-rtdApi
  • Topic/1221-LogginExtendedNew
  • Topic/1221-LoggingExtended
  • Topic/1279-quotaManagement
  • Topic/1292-FdsS3
  • Topic/1335-dotnet5Apis
  • Topic/1425-fhPrivileges
  • Topic/1453-userInvitation
  • Topic/1529-HandleExternalUserInvitation
  • Topic/1530-invitationUserManagement
  • Topic/1531-UseMangmntTableView
  • v1.0.0
  • v1.1.0
  • v1.10.0
  • v1.11.0
  • v1.11.1
  • v1.12.0
  • v1.13.0
  • v1.13.1
  • v1.14.0
  • v1.15.0
  • v1.15.1
  • v1.16.0
  • v1.16.1
  • v1.17.0
  • v1.17.1
  • v1.18.0
  • v1.19.0
  • v1.2.0
  • v1.2.1
  • v1.20.0
  • v1.20.1
  • v1.20.2
  • v1.21.0
  • v1.21.1
  • v1.22.0
  • v1.23.0
  • v1.23.1
  • v1.23.2
  • v1.23.3
  • v1.24.0
  • v1.24.1
  • v1.25.0
  • v1.25.1
  • v1.3.0
  • v1.4.0
  • v1.4.1
  • v1.5.0
  • v1.5.1
  • v1.6.0
  • v1.6.1
  • v1.6.2
  • v1.7.0
  • v1.7.1
  • v1.8.0
  • v1.9.0
  • v2.0.0
  • v2.0.1
  • v2.0.2
  • v2.1.0
  • v2.1.1
  • v2.1.2
  • v2.2.0
  • v2.2.1
  • v2.2.2
  • v2.2.3
  • v2.2.4
  • v2.2.5
  • v2.3.0
  • v2.4.0
  • v2.4.1
  • v2.4.2
  • v2.4.3
  • v2.5.0
  • v2.5.1
  • v2.5.2
  • v2.5.3
  • v2.5.4
  • v2.6.0
  • v2.6.1
  • v2.6.2
  • v2.7.0
  • v2.8.0
  • v2.8.1
  • v2.8.2
  • v2.8.3
  • v2.8.4
  • v2.9.0
  • v3.0.0
  • v3.0.1
  • v4.0.0
  • v4.0.1
  • v4.0.2
  • v4.0.3
  • v4.1.0
  • v4.1.1
  • v4.2.0
  • v4.2.1
  • v4.2.2
  • v4.2.3
  • v4.2.4
  • v4.2.5
  • v4.2.6
  • v4.2.7
  • v4.2.8
  • v4.3.0
  • v4.3.1
  • v4.3.2
  • v4.3.3
  • v4.3.4
  • v4.4.0
200 results
Show changes
Commits on Source (27)
Showing
with 692 additions and 60 deletions
......@@ -10,6 +10,16 @@ To use Kestrel you need to add the following NuGet packages:
* ```Microsoft.AspNetCore.Mvc```
* ```Microsoft.AspNetCore```
## Consul keys
The following Consul keys are required:
* "coscine/global/waterbutler_url"
* "coscine/global/rds_access_key"
* "coscine/global/rds_secret_key"
* "coscine/global/gitlabtoken"
* Look at cs/action Consul keys
## Https usage
Generate a developer certificate: ```dotnet dev-certs https```
......
......@@ -10,6 +10,16 @@ To use Kestrel you need to add the following NuGet packages:
* ```Microsoft.AspNetCore.Mvc```
* ```Microsoft.AspNetCore```
## Consul keys
The following Consul keys are required:
* "coscine/global/waterbutler_url"
* "coscine/global/rds_access_key"
* "coscine/global/rds_secret_key"
* "coscine/global/gitlabtoken"
* Look at cs/action Consul keys
## Https usage
Generate a developer certificate: ```dotnet dev-certs https```
......
......@@ -55,8 +55,11 @@
<Reference Include="Consul, Version=0.7.2.6, Culture=neutral, PublicKeyToken=20a6ad9a81df1d95, processorArchitecture=MSIL">
<HintPath>..\packages\Consul.0.7.2.6\lib\net45\Consul.dll</HintPath>
</Reference>
<Reference Include="Coscine.ApiCommons, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.ApiCommons.1.0.0\lib\net461\Coscine.ApiCommons.dll</HintPath>
<Reference Include="Coscine.Action, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.Action.1.1.2\lib\net461\Coscine.Action.dll</HintPath>
</Reference>
<Reference Include="Coscine.ApiCommons, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.ApiCommons.1.1.0\lib\net461\Coscine.ApiCommons.dll</HintPath>
</Reference>
<Reference Include="Coscine.Configuration, Version=1.4.0.0, Culture=neutral, PublicKeyToken=ce3d7a32d7dc1e5a, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.Configuration.1.4.0\lib\net461\Coscine.Configuration.dll</HintPath>
......@@ -64,6 +67,12 @@
<Reference Include="Coscine.Database, Version=1.4.0.0, Culture=neutral, PublicKeyToken=767d77427707b70a, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.Database.1.4.0\lib\net461\Coscine.Database.dll</HintPath>
</Reference>
<Reference Include="Coscine.ProxyApi, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.ProxyApi.1.2.0\lib\net461\Coscine.ProxyApi.dll</HintPath>
</Reference>
<Reference Include="Coscine.SharePoint.Webparts.Vue, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0fe8d3e516df6d98, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.SharePoint.Webparts.Vue.1.3.0\lib\net461\Coscine.SharePoint.Webparts.Vue.dll</HintPath>
</Reference>
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
</Reference>
......
......@@ -64,6 +64,7 @@ namespace Coscine.Api.Project.Tests
}
[Test]
public void TestControllerUpdate()
{
......@@ -138,6 +139,69 @@ namespace Coscine.Api.Project.Tests
projectModel.Delete(project);
}
[Test]
public void TestControllerStoreWithSubProject()
{
ProjectObject newProjectObject = new ProjectObject(Guid.NewGuid(), "NewProject", "NewDisplayName", "NewOrganisation", DateTime.Now, DateTime.Now.AddYears(1), "test2;test3");
var stream = ObjectFactory<ProjectObject>.SerializeToStream(newProjectObject);
FakeControllerContext(Users[0], stream);
var actionResult = Controller.Store();
OkObjectResult okObjectResult = (OkObjectResult)actionResult;
ProjectObject createdProjectObject = (ProjectObject)okObjectResult.Value;
ProjectObject newSubProjectObject = new ProjectObject(Guid.NewGuid(), "NewSubProject", "NewDisplayNameSub", "NewOrganisation", DateTime.Now, DateTime.Now.AddYears(1), "test2;test3", createdProjectObject.Id);
var subStream = ObjectFactory<ProjectObject>.SerializeToStream(newSubProjectObject);
FakeControllerContext(Users[0], subStream);
var subActionResult = Controller.Store();
OkObjectResult okSubObjectResult = (OkObjectResult)subActionResult;
ProjectObject createdSubProjectObject = (ProjectObject)okSubObjectResult.Value;
SubProjectModel subProjectModel = new SubProjectModel();
var subProjects = subProjectModel.GetAllWhere((x) => x.ProjectId == createdProjectObject.Id);
foreach(var subProject in subProjects)
{
Assert.IsTrue(subProject.SubProjectId == createdSubProjectObject.Id);
Assert.IsTrue(subProject.ProjectId == createdProjectObject.Id);
}
// Cleanup
stream.Close();
subStream.Close();
ProjectModel projectModel = new ProjectModel();
var project = projectModel.GetById(createdProjectObject.Id);
SubProjectModel subProjectModel1 = new SubProjectModel();
var subProjects1 = subProjectModel1.GetAllWhere((x) => x.ProjectId == project.Id);
foreach (var subProject in subProjects1)
{
subProjectModel1.Delete(subProject);
}
ProjectRoleModel projectRoleModel = new ProjectRoleModel();
var projectRoles = projectRoleModel.GetAllWhere((x) => x.ProjectId == project.Id);
foreach (var projectRole in projectRoles)
{
projectRoleModel.Delete(projectRole);
}
projectModel.Delete(project);
ProjectModel projectModel2 = new ProjectModel();
var project2 = projectModel2.GetById(createdSubProjectObject.Id);
ProjectRoleModel projectRoleModel2 = new ProjectRoleModel();
var projectRoles2 = projectRoleModel2.GetAllWhere((x) => x.ProjectId == project2.Id);
foreach (var projectRole in projectRoles2)
{
projectRoleModel2.Delete(projectRole);
}
projectModel2.Delete(project2);
}
[Test]
public void CountTest()
{
......
......@@ -9,8 +9,8 @@ using System.Reflection;
[assembly: AssemblyDescription("Project.Tests is a part of the CoScInE group.")]
[assembly: AssemblyCompany("IT Center, RWTH Aachen University")]
[assembly: AssemblyProduct("Project.Tests")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0.0")]
[assembly: AssemblyCopyright("2019 IT Center, RWTH Aachen University")]
......@@ -4,9 +4,12 @@
<package id="AutoMapper.Extensions.Microsoft.DependencyInjection" version="6.0.0" targetFramework="net472" />
<package id="Castle.Core" version="4.4.0" targetFramework="net472" />
<package id="Consul" version="0.7.2.6" targetFramework="net472" />
<package id="Coscine.ApiCommons" version="1.0.0" targetFramework="net472" />
<package id="Coscine.Action" version="1.1.2" targetFramework="net472" />
<package id="Coscine.ApiCommons" version="1.1.0" targetFramework="net472" />
<package id="Coscine.Configuration" version="1.4.0" targetFramework="net472" />
<package id="Coscine.Database" version="1.4.0" targetFramework="net472" />
<package id="Coscine.ProxyApi" version="1.2.0" targetFramework="net472" />
<package id="Coscine.SharePoint.Webparts.Vue" version="1.3.0" targetFramework="net472" />
<package id="EntityFramework" version="6.2.0" targetFramework="net472" />
<package id="linq2db" version="2.6.4" targetFramework="net472" />
<package id="linq2db.SqlServer" version="2.6.4" targetFramework="net472" />
......
using Coscine.Api.Project.Models;
using Coscine.Api.Project.ReturnObjects;
using Coscine.ApiCommons;
using Coscine.ApiCommons.Utils;
using Coscine.Configuration;
using Coscine.Database.Model;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Controllers
{
public class DataSourceController : Controller
{
private readonly IConfiguration _configuration;
private readonly JWTHandler _jwtHandler;
private static readonly HttpClient Client = new HttpClient();
private readonly Authenticator _authenticator;
private readonly ResourceModel _resourceModel;
public DataSourceController()
{
_configuration = Program.Configuration;
_jwtHandler = new JWTHandler(_configuration);
_authenticator = new Authenticator(this, _configuration);
_resourceModel = new ResourceModel();
}
// inferring a ../ (urlencoded) can manipulate the url.
// However the constructed signature for s3 won't match and it will not be resolved.
// This may be a problem for other provider!
[HttpGet("[controller]/{resourceId}/{*path}")]
public async Task<IActionResult> Get(string resourceId, string path)
{
if (!Guid.TryParse(resourceId, out Guid resouceGuid))
{
return BadRequest($"{resourceId} is not a guid.");
}
Resource resource;
try
{
resource = _resourceModel.GetById(resouceGuid);
if (resource == null)
{
return NotFound($"Could not find resource with id: {resourceId}");
}
}
catch (Exception)
{
return NotFound($"Could not find resource with id: {resourceId}");
}
var user = _authenticator.GetUserFromToken();
if (!_resourceModel.OwnsResource(user, resource))
{
return Forbid($"The user does not own the resource {resourceId}");
}
if (resource.Type == null)
{
ResourceTypeModel resourceTypeModel = new ResourceTypeModel();
resource.Type = resourceTypeModel.GetById(resource.TypeId);
}
string authHeader = null;
if (resource.Type.DisplayName.ToLower() == "rds")
{
authHeader = BuildRdsAuthHeader(resource.ExternalId);
}
else if (resource.Type.DisplayName.ToLower() == "gitlab")
{
authHeader = BuildGitlabAuthHeader(resource.ExternalId, resource.Url);
}
if (authHeader != null)
{
// If the path is null, an empty string is added.
string url = $"{_configuration.GetString("coscine/global/waterbutler_url")}{resource.Type.DisplayName.ToLower()}/{path}";
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authHeader);
// Thread safe according to msdn and HttpCompletionOption sets it to get only headers first.
var response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
if (response.IsSuccessStatusCode)
{
if (response.Content.Headers.Contains("Content-Disposition"))
{
return File(await response.Content.ReadAsStreamAsync(),
response.Content.Headers.GetValues("Content-Type").First());
}
else
{
var data = JObject.Parse(await response.Content.ReadAsStringAsync())["data"];
return Ok(new WaterbutlerObject(path, data));
}
}
else
{
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return NotFound($"Could not find object for: \"{path}\".");
}
else
if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
return Forbid("Not allowed to access the datasource.");
}
else
{
return BadRequest($"Error in communication with waterbutler: {response.StatusCode}");
}
}
}
else
{
return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
}
}
private string BuildWaterbutlerPayload(Dictionary<string, object> auth, Dictionary<string, object> credentials, Dictionary<string, object> settings)
{
var data = new Dictionary<string, object>
{
{ "auth", auth },
{ "credentials", credentials },
{ "settings", settings },
{ "callback_url", "rwth-aachen.de" }
};
var payload = new JwtPayload
{
{ "data", data }
};
return _jwtHandler.GenerateJwtToken(payload);
}
private string BuildRdsAuthHeader(string bucketname)
{
var auth = new Dictionary<string, object>();
var credentials = new Dictionary<string, object>
{
{ "access_key", _configuration.GetString("coscine/global/rds_access_key") },
{ "secret_key", _configuration.GetString("coscine/global/rds_secret_key") }
};
var settings = new Dictionary<string, object>
{
{ "bucket", bucketname }
};
return BuildWaterbutlerPayload(auth, credentials, settings);
}
private string BuildGitlabAuthHeader(string externalId, string url)
{
var auth = new Dictionary<string, object>();
var credentials = new Dictionary<string, object>
{
{ "token", _configuration.GetString("coscine/global/gitlabtoken") }
};
var settings = new Dictionary<string, object>
{
{"owner", "Tester"},
{"repo", url},
{ "repo_id", externalId},
{ "host", "https://git.rwth-aachen.de"}
};
return BuildWaterbutlerPayload(auth, credentials, settings);
}
}
}
......@@ -6,8 +6,8 @@ using Coscine.Api.Project.ReturnObjects;
using Coscine.ApiCommons;
using Coscine.ApiCommons.Exceptions;
using Coscine.ApiCommons.Factories;
using Coscine.Database.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.SharePoint;
using System;
using System.Collections.Generic;
using System.Linq;
......@@ -17,16 +17,18 @@ namespace Coscine.Api.Project.Controllers
public class ProjectController : Controller
{
private readonly Authenticator _authenticator;
private readonly List<IProjectAction> projectActions;
private readonly List<IProjectAction> _projectActions;
private readonly ProjectModel _projectModel;
public ProjectController()
{
_authenticator = new Authenticator(this, Program.Configuration);
projectActions = new List<IProjectAction>()
_projectActions = new List<IProjectAction>()
{
new PIDAction(),
new SharePointSiteAction()
};
_projectModel = new ProjectModel();
}
[Route("[controller]")]
......@@ -34,8 +36,7 @@ namespace Coscine.Api.Project.Controllers
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ProjectModel projectModel = new ProjectModel();
return projectModel.GetAllWhere((project) =>
return _projectModel.GetAllWhere((project) =>
(from projectRole in project.ProjectRolesProjectIdIds
where projectRole.User == user
&& projectRole.Role.DisplayName == "Owner"
......@@ -49,9 +50,46 @@ namespace Coscine.Api.Project.Controllers
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ProjectModel projectModel = new ProjectModel();
var project = projectModel.GetById(Guid.Parse(id));
return new ProjectObject(project.Id, project.Description, project.DisplayName, project.Organization, project.StartDate, project.EndDate, project.Keywords);
var project = _projectModel.GetById(Guid.Parse(id));
if (_projectModel.CanSeeProject(user, project))
{
return new ProjectObject(project.Id, project.Description, project.DisplayName, project.Organization, project.StartDate, project.EndDate, project.Keywords);
}
else
{
throw new UnauthorizedAccessException("User is not allowed to see given project Id!");
}
}));
}
[HttpGet("[controller]/{id}/resources")]
public IActionResult GetResources(string id)
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
var project = _projectModel.GetById(Guid.Parse(id));
ResourceModel resourceModel = new ResourceModel();
ResourceTypeModel resourceTypeModel = new ResourceTypeModel();
if (_projectModel.CanSeeProject(user, project))
{
return resourceModel.GetAllWhere((resource) =>
(from projectResource in resource.ProjectResourceResourceIdIds
where projectResource.ProjectId == project.Id
select projectResource).Any())
.Select((resource) =>
{
ResourceType resourceType = resource.Type;
if (resourceType == null)
{
resourceType = resourceTypeModel.GetById(resource.TypeId);
}
return new ResourceObject(resource.Id, resource.ExternalId, resource.Url, new ResourceTypeObject(resourceType.Id, resourceType.DisplayName));
});
}
else
{
throw new UnauthorizedAccessException("User cannot see resources of given project!");
}
}));
}
......@@ -61,11 +99,10 @@ namespace Coscine.Api.Project.Controllers
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ProjectObject projectObject = ObjectFactory<ProjectObject>.DeserializeFromStream(Request.Body);
ProjectModel projectModel = new ProjectModel();
var project = projectModel.GetById(Guid.Parse(id));
if(projectModel.OwnsProject(user, project))
var project = _projectModel.GetById(Guid.Parse(id));
if(_projectModel.OwnsProject(user, project))
{
return projectModel.UpdateByObject(project, projectObject);
return _projectModel.UpdateByObject(project, projectObject);
}
else
{
......@@ -80,8 +117,15 @@ namespace Coscine.Api.Project.Controllers
return base.Ok(_authenticator.ValidateAndExecute((user) =>
{
ProjectObject projectObject = ObjectFactory<ProjectObject>.DeserializeFromStream(Request.Body);
ProjectModel projectModel = new ProjectModel();
var project = projectModel.StoreFromObject(projectObject, user);
var project = _projectModel.StoreFromObject(projectObject, user);
if (projectObject.ParentId != null
&& projectObject.ParentId != new Guid()
&& _projectModel.OwnsProject(user, _projectModel.GetById(projectObject.ParentId))) // for now, only an owner can add subprojects to projects
{
SubProjectModel subProjectModel = new SubProjectModel();
subProjectModel.LinkSubProject(projectObject.ParentId, project.Id);
}
FireEvents((projectAction, projectEventArgs) => projectAction.OnProjectCreate(project, projectEventArgs));
......@@ -91,24 +135,10 @@ namespace Coscine.Api.Project.Controllers
private void FireEvents(Action<IProjectAction, ProjectEventArgs> eventAction)
{
var sharePointSite = Request.Headers["Referer"];
SPUserToken systemAccount = SPUserToken.SystemAccount;
using (SPSite site = new SPSite(sharePointSite, systemAccount))
ProjectEventArgs projectEventArgs = new ProjectEventArgs(Program.Configuration, new object[0]);
foreach (var projectAction in _projectActions)
{
using (SPWeb web = site.OpenWeb())
{
SPContext context = SPContext.GetContext(web);
object[] args = new object[]
{
context
};
ProjectEventArgs projectEventArgs = new ProjectEventArgs(Program.Configuration, args);
foreach (var projectAction in projectActions)
{
eventAction(projectAction, projectEventArgs);
}
}
eventAction(projectAction, projectEventArgs);
}
}
}
......
using Coscine.Api.Project.Models;
using Coscine.Api.Project.ReturnObjects;
using Coscine.ApiCommons;
using Coscine.ApiCommons.Exceptions;
using Coscine.ApiCommons.Factories;
using Coscine.Database.Model;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Controllers
{
public class ProjectRoleController : Controller
{
private readonly Authenticator _authenticator;
private readonly ProjectRoleModel _projectRoleModel;
public ProjectRoleController()
{
_authenticator = new Authenticator(this, Program.Configuration);
_projectRoleModel = new ProjectRoleModel();
}
[Route("[controller]/{projectId}")]
public IActionResult Index(string projectId)
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
UserModel userModel = new UserModel();
RoleModel roleModel = new RoleModel();
ProjectModel projectModel = new ProjectModel();
Guid.TryParse(projectId, out Guid projectIdGuid);
if (projectModel.OwnsProject(user, projectModel.GetById(projectIdGuid)))
{
return _projectRoleModel.GetAllWhere((projectRole) =>
(projectRole.ProjectId == projectIdGuid)
).Select((projectRole) =>
{
User userInst = projectRole.User;
if (userInst == null)
{
userInst = userModel.GetById(projectRole.UserId);
}
Role role = projectRole.Role;
if (role == null)
{
role = roleModel.GetById(projectRole.RoleId);
}
return new ProjectRoleObject(projectRole.ProjectId, new UserObject(userInst.Id, userInst.DisplayName), new RoleObject(role.Id, role.DisplayName));
});
}
else
{
throw new UnauthorizedAccessException("User is not allowed to list all users to the given project!");
}
}));
}
[HttpPost("[controller]")]
public IActionResult Set()
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ProjectRoleObject projectRoleObject = ObjectFactory<ProjectRoleObject>.DeserializeFromStream(Request.Body);
ProjectModel projectModel = new ProjectModel();
if (projectModel.OwnsProject(user, projectModel.GetById(projectRoleObject.ProjectId)))
{
return _projectRoleModel.SetFromObject(projectRoleObject);
}
else
{
throw new NotAuthorizedException("The user is not authorized to store a project role to the given project!");
}
}));
}
[HttpDelete("[controller]/project/{projectId}/user/{userId}/role/{roleId}")]
public IActionResult Delete(Guid projectId, Guid userId, Guid roleId)
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ProjectModel projectModel = new ProjectModel();
if (projectModel.OwnsProject(user, projectModel.GetById(projectId)))
{
return _projectRoleModel.Delete(_projectRoleModel.GetWhere((projectRole) =>
projectRole.ProjectId == projectId
&& projectRole.UserId == userId
&& projectRole.RoleId == roleId));
}
else
{
throw new NotAuthorizedException("The user is not authorized to delete a project role for the given project!");
}
}));
}
}
}
......@@ -12,10 +12,12 @@ namespace Coscine.Api.Project.Controllers
public class ResourceController : Controller
{
private readonly Authenticator _authenticator;
private readonly ResourceModel _resourceModel;
public ResourceController()
{
_authenticator = new Authenticator(this, Program.Configuration);
_resourceModel = new ResourceModel();
}
[Route("[controller]")]
......@@ -23,8 +25,7 @@ namespace Coscine.Api.Project.Controllers
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ResourceModel resourceModel = new ResourceModel();
return resourceModel.GetAllWhere((resource) =>
return _resourceModel.GetAllWhere((resource) =>
(from projectResource in resource.ProjectResourceResourceIdIds
where (from projectRole in projectResource.Project.ProjectRolesProjectIdIds
where projectRole.User == user
......@@ -41,9 +42,8 @@ namespace Coscine.Api.Project.Controllers
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ResourceModel resourceModel = new ResourceModel();
var resource = resourceModel.GetById(Guid.Parse(id));
if (resourceModel.OwnsResource(user, resource))
var resource = _resourceModel.GetById(Guid.Parse(id));
if (_resourceModel.OwnsResource(user, resource))
{
//TODO: Find out why resource.Type is not set
if(resource.Type == null)
......@@ -66,11 +66,10 @@ namespace Coscine.Api.Project.Controllers
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ResourceObject resourceObject = ObjectFactory<ResourceObject>.DeserializeFromStream(Request.Body);
ResourceModel resourceModel = new ResourceModel();
var resource = resourceModel.GetById(Guid.Parse(id));
if (resourceModel.OwnsResource(user, resource))
var resource = _resourceModel.GetById(Guid.Parse(id));
if (_resourceModel.OwnsResource(user, resource))
{
return resourceModel.UpdateByObject(resource, resourceObject);
return _resourceModel.UpdateByObject(resource, resourceObject);
}
else
{
......@@ -90,8 +89,7 @@ namespace Coscine.Api.Project.Controllers
var project = projectModel.GetById(Guid.Parse(projectId));
if (projectModel.OwnsProject(user, project))
{
ResourceModel resourceModel = new ResourceModel();
var resource = resourceModel.StoreFromObject(resourceObject);
var resource = _resourceModel.StoreFromObject(resourceObject);
projectModel.AddResource(project, resource);
......
using Coscine.Api.Project.Models;
using Coscine.Api.Project.ReturnObjects;
using Coscine.ApiCommons;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Controllers
{
public class ResourceTypeController : Controller
{
private readonly Authenticator _authenticator;
private readonly ResourceTypeModel _resourceTypeModel;
public ResourceTypeController()
{
_authenticator = new Authenticator(this, Program.Configuration);
_resourceTypeModel = new ResourceTypeModel();
}
[Route("[controller]")]
public IActionResult Index()
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
return _resourceTypeModel.GetAll().Select((resourceType) => new ResourceTypeObject(resourceType.Id, resourceType.DisplayName));
}));
}
}
}
using Coscine.Api.Project.Models;
using Coscine.Api.Project.ReturnObjects;
using Coscine.ApiCommons;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Controllers
{
public class RoleController : Controller
{
private readonly Authenticator _authenticator;
private readonly RoleModel _roleModel;
public RoleController()
{
_authenticator = new Authenticator(this, Program.Configuration);
_roleModel = new RoleModel();
}
[Route("[controller]")]
public IActionResult Index()
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
return _roleModel.GetAll().Select((role) => new RoleObject(role.Id, role.DisplayName));
}));
}
}
}
using Coscine.Api.Project.Models;
using Coscine.Api.Project.ReturnObjects;
using Coscine.ApiCommons;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;
namespace Coscine.Api.Project.Controllers
{
public class SubProjectController : Controller
{
private readonly Authenticator _authenticator;
private readonly SubProjectModel _subProjectModel;
public SubProjectController()
{
_authenticator = new Authenticator(this, Program.Configuration);
_subProjectModel = new SubProjectModel();
}
[HttpGet("[controller]/{parentId}")]
public IActionResult Get(string parentId)
{
return Ok(_authenticator.ValidateAndExecute((user) =>
{
Guid parentGuid = new Guid(parentId);
ProjectModel projectModel = new ProjectModel();
if (projectModel.CanSeeProject(user, projectModel.GetById(parentGuid)))
{
var subProjects = _subProjectModel.GetAllWhere((subProjectM) => (subProjectM.ProjectId == parentGuid))
.Select((subProject) => projectModel.GetById(subProject.SubProjectId))
.Select((project) => new ProjectObject(project.Id, project.Description, project.DisplayName, project.Organization, project.StartDate, project.EndDate, project.Keywords, parentGuid));
return subProjects;
}
else
{
throw new UnauthorizedAccessException("User is not allowed to create a subproject for the given project id!");
}
}));
}
}
}
......@@ -47,6 +47,16 @@ namespace Coscine.Api.Project.Models
return projectRole;
}
public bool CanSeeProject(User user, Coscine.Database.Model.Project project)
{
return DatabaseConnection.ConnectToDatabase((db) => (from relation in db.ProjectRoles
where relation.Project == project
&& relation.User == user
&& (relation.Role.DisplayName == "Owner"
|| relation.Role.DisplayName == "Member")
select relation).Any());
}
public bool OwnsProject(User user, Coscine.Database.Model.Project project)
{
return DatabaseConnection.ConnectToDatabase((db) => (from relation in db.ProjectRoles
......
using Coscine.ApiCommons.Models;
using Coscine.Api.Project.ReturnObjects;
using Coscine.ApiCommons.Models;
using Coscine.Database.Model;
using LinqToDB;
using System;
using System.Linq;
using System.Linq.Expressions;
namespace Coscine.Api.Project.Models
......@@ -12,6 +14,27 @@ namespace Coscine.Api.Project.Models
{
}
public ProjectRole SetFromObject(ProjectRoleObject projectRoleObject)
{
// Remove existing roles if they exist
var existingRoles = GetAllWhere((dbProjectRole) => dbProjectRole.ProjectId == projectRoleObject.ProjectId && dbProjectRole.UserId == projectRoleObject.User.Id);
if(existingRoles.Count() > 0)
{
foreach(var role in existingRoles)
{
Delete(role);
}
}
ProjectRole projectRole = new ProjectRole()
{
ProjectId = projectRoleObject.ProjectId,
UserId = projectRoleObject.User.Id,
RoleId = projectRoleObject.Role.Id
};
Insert(projectRole);
return projectRole;
}
public override Expression<Func<ProjectRole, Guid>> GetIdFromObject()
{
......
using System;
using System.Linq.Expressions;
using Coscine.ApiCommons.Models;
using Coscine.Database.Model;
using LinqToDB;
namespace Coscine.Api.Project.Models
{
public class SubProjectModel : DatabaseModel<SubProject>
{
public SubProjectModel() : base(Program.Configuration)
{
}
public override Expression<Func<SubProject, Guid>> GetIdFromObject()
{
return databaseObject => databaseObject.RelationId;
}
public override ITable<SubProject> GetITableFromDatabase(CoscineDB db)
{
return db.SubProjects;
}
public void LinkSubProject(Guid parentId, Guid childId)
{
Insert(new SubProject()
{
ProjectId = parentId,
SubProjectId = childId,
});
}
public override void SetObjectId(SubProject databaseObject, Guid id)
{
databaseObject.RelationId = id;
}
}
}
......@@ -45,11 +45,11 @@
<Reference Include="Consul, Version=0.7.2.6, Culture=neutral, PublicKeyToken=20a6ad9a81df1d95, processorArchitecture=MSIL">
<HintPath>..\packages\Consul.0.7.2.6\lib\net45\Consul.dll</HintPath>
</Reference>
<Reference Include="Coscine.Action, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.Action.1.0.0\lib\net461\Coscine.Action.dll</HintPath>
<Reference Include="Coscine.Action, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.Action.1.1.2\lib\net461\Coscine.Action.dll</HintPath>
</Reference>
<Reference Include="Coscine.ApiCommons, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.ApiCommons.1.0.0\lib\net461\Coscine.ApiCommons.dll</HintPath>
<Reference Include="Coscine.ApiCommons, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.ApiCommons.1.1.0\lib\net461\Coscine.ApiCommons.dll</HintPath>
</Reference>
<Reference Include="Coscine.Configuration, Version=1.4.0.0, Culture=neutral, PublicKeyToken=ce3d7a32d7dc1e5a, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.Configuration.1.4.0\lib\net461\Coscine.Configuration.dll</HintPath>
......@@ -353,7 +353,6 @@
<Reference Include="Microsoft.Net.Http.Headers, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Net.Http.Headers.2.2.0\lib\netstandard2.0\Microsoft.Net.Http.Headers.dll</HintPath>
</Reference>
<Reference Include="Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Win32.Registry, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Win32.Registry.4.5.0\lib\net461\Microsoft.Win32.Registry.dll</HintPath>
</Reference>
......@@ -564,20 +563,30 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\DataSourceController.cs" />
<Compile Include="Controllers\ProjectController.cs" />
<Compile Include="Controllers\ResourceController.cs" />
<Compile Include="Controllers\ResourceTypeController.cs" />
<Compile Include="Controllers\RoleController.cs" />
<Compile Include="Controllers\SubProjectController.cs" />
<Compile Include="Controllers\ProjectRoleController.cs" />
<Compile Include="Models\ProjectModel.cs" />
<Compile Include="Models\ProjectResourceModel.cs" />
<Compile Include="Models\ProjectRoleModel.cs" />
<Compile Include="Models\ResourceModel.cs" />
<Compile Include="Models\ResourceTypeModel.cs" />
<Compile Include="Models\RoleModel.cs" />
<Compile Include="Models\SubProjectModel.cs" />
<Compile Include="Models\UserModel.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReturnObjects\ProjectObject.cs" />
<Compile Include="ReturnObjects\ProjectRoleObject.cs" />
<Compile Include="ReturnObjects\ResourceObject.cs" />
<Compile Include="ReturnObjects\ResourceTypeObject.cs" />
<Compile Include="ReturnObjects\RoleObject.cs" />
<Compile Include="ReturnObjects\UserObject.cs" />
<Compile Include="ReturnObjects\WaterbutlerFolder.cs" />
<Compile Include="Startup.cs" />
</ItemGroup>
<ItemGroup>
......
......@@ -9,8 +9,8 @@ using System.Reflection;
[assembly: AssemblyDescription("Project is a part of the CoScInE group.")]
[assembly: AssemblyCompany("IT Center, RWTH Aachen University")]
[assembly: AssemblyProduct("Project")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0.0")]
[assembly: AssemblyCopyright("2019 IT Center, RWTH Aachen University")]
using Coscine.ApiCommons.ReturnObjects;
using Coscine.Api.Project.Models;
using Coscine.ApiCommons.ReturnObjects;
using System;
namespace Coscine.Api.Project.ReturnObjects
......@@ -16,7 +17,9 @@ namespace Coscine.Api.Project.ReturnObjects
public DateTime EndDate { get; set; }
public string Keywords { get; set; }
public ProjectObject(Guid id, string description, string displayName, string organisation, DateTime startDate, DateTime endDate, string keywords)
public Guid ParentId { get; set; }
public ProjectObject(Guid id, string description, string displayName, string organisation, DateTime startDate, DateTime endDate, string keywords, Guid parentId = new Guid())
{
Id = id;
Description = description;
......@@ -25,7 +28,7 @@ namespace Coscine.Api.Project.ReturnObjects
StartDate = startDate;
EndDate = endDate;
Keywords = keywords;
ParentId = parentId;
}
}
}
using Coscine.ApiCommons.ReturnObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project.ReturnObjects
{
[Serializable]
public class ProjectRoleObject : IReturnObject
{
public Guid ProjectId { get; set; }
public UserObject User { get; set; }
public RoleObject Role { get; set; }
public ProjectRoleObject(Guid projectId, UserObject user, RoleObject role)
{
ProjectId = projectId;
User = user;
Role = role;
}
}
}