Commit e21dbddb authored by Benedikt Heinrichs's avatar Benedikt Heinrichs

New: Implement ProjectController

parent ad8919d3
......@@ -229,7 +229,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="HomeControllerTests.cs" />
<Compile Include="ProjectControllerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
......
......@@ -7,15 +7,10 @@ namespace Coscine.Api.Project.Tests
{
[TestFixture]
public class HomeControllerTests
public class ProjectControllerTests
{
private readonly ProjectController _projectController = new ProjectController();
[Test]
public void GreetTest()
{
}
[Test]
public void IndexTest()
{
......
using Microsoft.AspNetCore.Mvc;
using Coscine.Api.Project.Models;
using Coscine.Database.Model;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
......@@ -17,14 +19,45 @@ namespace Coscine.Api.Project
}
public bool ValidUser()
{
try
{
GetUserFromToken();
}
catch (Exception)
{
return false;
}
return true;
}
public User GetUserFromToken()
{
var bearer = _controller.Request.Headers["bearer"];
if (!string.IsNullOrWhiteSpace(bearer))
{
// Todo: Validate User
return true;
JWTHandler jwtHandler = new JWTHandler(Program.Configurator.Configuration);
var claims = jwtHandler.GetContents(bearer);
var userClaim = (from claimObj in claims
where claimObj.Type == "UserId"
select claimObj).First();
UserModel userModel = new UserModel();
return userModel.GetById(Guid.Parse(userClaim.Value));
}
return false;
else
{
throw new ArgumentException("Bearer Token is not set!");
}
}
public void ValidateAndExecute(Action<User> action)
{
action.Invoke(GetUserFromToken());
}
public T ValidateAndExecute<T>(Func<User, T> func)
{
return func.Invoke(GetUserFromToken());
}
// Todo: Add roles as parameter
......
......@@ -5,7 +5,7 @@ using System.Net.NetworkInformation;
namespace Coscine.Api.Project
{
class Configurator
public class Configurator
{
public ApplicationInformation ApplicationInformation { get; set; } = new ApplicationInformation();
public IConfiguration Configuration { get; set; }
......
using Microsoft.AspNetCore.Mvc;
using Coscine.Api.Project.Exceptions;
using Coscine.Api.Project.Factories;
using Coscine.Api.Project.Models;
using Coscine.Api.Project.ReturnObjects;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;
namespace Coscine.Api.Project.Controllers
{
......@@ -14,33 +20,85 @@ namespace Coscine.Api.Project.Controllers
[Route("[controller]")]
public IActionResult Index()
{
return Ok("Hello World from a controller");
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ProjectModel projectModel = new ProjectModel();
return projectModel.GetAllWhere((project) =>
{
return (from projectRole in project.ProjectRolesProjectIdIds
where projectRole.User == user
&& projectRole.Role.DisplayName == "Owner"
select projectRole).Any();
}).Select((project) =>
{
return new ProjectObject(project.Id, project.Description, project.DisplayName, project.Organization);
});
}));
}
//[Route("[controller]/greet/{username}")] would also work, but would take all commands
[HttpGet("[controller]/{id}")]
public IActionResult Get(string id)
{
return Ok(id);
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);
}));
}
//[Route("[controller]/greet/{username}")] would also work, but would take all commands
[HttpPost("[controller]/{id}")]
public IActionResult Update(string id)
{
return Ok(id);
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))
{
return projectModel.Update(project);
}
else
{
throw new NotAuthorizedException("The user is not authorized to perform an update on the selected project");
}
}));
}
[HttpPut("[controller]")]
[HttpPost("[controller]")]
public IActionResult Store()
{
return Ok();
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ProjectObject projectObject = ObjectFactory<ProjectObject>.DeserializeFromStream(Request.Body);
ProjectModel projectModel = new ProjectModel();
var project = projectModel.StoreFromObject(projectObject, user);
return new ProjectObject(project.Id, project.Description, project.DisplayName, project.Organization);
}));
}
[HttpPut("[controller]/{id}/resource/{resource_id}")]
[HttpPost("[controller]/{id}/resource/{resource_id}")]
public IActionResult AddResource(string id, string resource_id)
{
return Ok(id);
return Ok(_authenticator.ValidateAndExecute((user) =>
{
ProjectModel projectModel = new ProjectModel();
var project = projectModel.GetById(Guid.Parse(id));
ResourceModel resourceModel = new ResourceModel();
var resource = resourceModel.GetById(Guid.Parse(resource_id));
if (projectModel.OwnsProject(user, project) && resourceModel.OwnsResource(user, resource))
{
projectModel.AddResource(project, resource);
return true;
}
else
{
throw new NotAuthorizedException("User is not authorized to add resource to project!");
}
}));
}
}
}
using Coscine.Configuration;
using Coscine.Database.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project
{
public class DatabaseConnection
{
private IConfiguration _configuration;
public DatabaseConnection(IConfiguration configuration)
{
_configuration = configuration;
}
private const string DbDataSourceKey = "coscine/global/db_data_source";
private const string DbNameKey = "coscine/global/db_name";
private const string DbUserIdKey = "coscine/global/db_user_id";
private const string DbPasswordKey = "coscine/global/db_password";
private string GetDbConnectionString()
{
var dbDataSource = _configuration.GetString(DbDataSourceKey);
var dbDatabase = _configuration.GetString(DbNameKey);
var dbUserId = _configuration.GetString(DbUserIdKey);
var dbPassword = _configuration.GetString(DbPasswordKey);
return $"Data Source={dbDataSource}; Database={dbDatabase}; User Id={dbUserId}; Password={dbPassword};";
}
private string GetProviderName()
{
return "SqlServer.2008";
}
public void ConnectToDatabase(Action<CoscineDB> action)
{
using (var coscineDB = new CoscineDB(GetProviderName(), GetDbConnectionString()))
{
action.Invoke(coscineDB);
}
}
public T ConnectToDatabase<T>(Func<CoscineDB, T> func)
{
T result;
using (var coscineDB = new CoscineDB(GetProviderName(), GetDbConnectionString()))
{
result = func.Invoke(coscineDB);
}
return result;
}
}
}
......@@ -4,16 +4,12 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Models
namespace Coscine.Api.Project.Exceptions
{
public class Project
public class InvalidTokenException : Exception
{
// TODO: Implement checking
public bool OwnsProject(User user)
public InvalidTokenException(string message) : base(message)
{
return true;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Exceptions
{
public class NotAuthorizedException : Exception
{
public NotAuthorizedException(string message) : base(message)
{
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using Coscine.Api.Project.ReturnObjects;
namespace Coscine.Api.Project.Factories
{
public class ObjectFactory<T>
{
public static MemoryStream SerializeToStream(T o)
{
MemoryStream stream = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, o);
return stream;
}
public static T DeserializeFromStream(MemoryStream stream)
{
IFormatter formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
T o = (T) formatter.Deserialize(stream);
return o;
}
public static T DeserializeFromStream(Stream body)
{
MemoryStream memoryStream = new MemoryStream();
body.CopyTo(memoryStream);
T o = DeserializeFromStream(memoryStream);
memoryStream.Close();
return o;
}
}
}
using Coscine.Api.Project.Exceptions;
using Coscine.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project
{
public class JWTHandler
{
private readonly IConfiguration _configuration;
private readonly JwtSecurityTokenHandler _jwtSecurityTokenHandler;
public JWTHandler(IConfiguration configuration)
{
_configuration = configuration;
_jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
}
public bool ValidToken(string token)
{
string secretKey = _configuration.GetString("coscine/global/jwtsecret");
if (secretKey == null)
{
throw new ArgumentNullException("JWT Secret Configuration value is not set!");
}
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
TokenValidationParameters tokenValidationParameters = new TokenValidationParameters();
tokenValidationParameters.TokenDecryptionKey = securityKey;
try
{
_jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken securityToken);
}
catch(Exception)
{
return false;
}
return true;
}
public IEnumerable<Claim> GetContents(string jwt)
{
if (ValidToken(jwt))
{
var token = _jwtSecurityTokenHandler.ReadJwtToken(jwt);
return token.Claims;
}
else
{
throw new InvalidTokenException("Invalid token!");
}
}
}
}
using Coscine.Configuration;
using Coscine.Database.Model;
using LinqToDB;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Models
{
public abstract class DatabaseModel<T>
{
public DatabaseConnection DatabaseConnection { get; set; }
public DatabaseModel(IConfiguration configuration)
{
DatabaseConnection = new DatabaseConnection(configuration);
}
public abstract Guid GetIdFromObject(T databaseObject);
public abstract ITable<T> GetITableFromDatabase(CoscineDB db);
public T GetById(Guid id)
{
return DatabaseConnection.ConnectToDatabase((db) =>
{
return
(from tableEntry in GetITableFromDatabase(db)
where GetIdFromObject(tableEntry) == id
select tableEntry).First();
});
}
public T GetWhere(Func<T, bool> whereClause)
{
return DatabaseConnection.ConnectToDatabase((db) =>
{
return
(from tableEntry in GetITableFromDatabase(db)
where whereClause.Invoke(tableEntry)
select tableEntry).First();
});
}
public IEnumerable<T> GetAll()
{
return DatabaseConnection.ConnectToDatabase((db) =>
{
return
(from tableEntry in GetITableFromDatabase(db)
select tableEntry).ToList();
});
}
public IEnumerable<T> GetAllWhere(Func<T, bool> whereClause)
{
return DatabaseConnection.ConnectToDatabase((db) =>
{
return
(from tableEntry in GetITableFromDatabase(db)
where whereClause.Invoke(tableEntry)
select tableEntry).ToList();
});
}
public int Update(T databaseObject)
{
return DatabaseConnection.ConnectToDatabase((db) =>
{
return db.Update(databaseObject);
});
}
public int Insert(T databaseObject)
{
return DatabaseConnection.ConnectToDatabase((db) =>
{
return db.Insert(databaseObject);
});
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Coscine.Api.Project.Exceptions;
using Coscine.Api.Project.ReturnObjects;
using Coscine.Database.Model;
using LinqToDB;
namespace Coscine.Api.Project.Models
{
public class ProjectModel : DatabaseModel<Coscine.Database.Model.Project>
{
public ProjectModel() : base(Program.Configurator.Configuration)
{
}
public Coscine.Database.Model.Project StoreFromObject(ProjectObject projectObject, User user)
{
Coscine.Database.Model.Project project = new Coscine.Database.Model.Project()
{
Description = projectObject.Description,
DisplayName = projectObject.DisplayName,
Organization = projectObject.Organization
};
Insert(project);
SetOwner(project, user);
return project;
}
public void SetOwner(Coscine.Database.Model.Project project, User user)
{
project.ProjectRolesProjectIdIds.Append(new ProjectRole()
{
Project = project,
User = user,
Role = new RoleModel().GetWhere((role) =>
{
return role.DisplayName == "Owner";
})
});
Update(project);
}
public bool OwnsProject(User user, Coscine.Database.Model.Project project)
{
return DatabaseConnection.ConnectToDatabase((db) =>
{
return (from relation in db.ProjectRoles
where relation.Project == project
&& relation.User == user
&& relation.Role.DisplayName == "Owner"
select relation).Any();
});
}
public void AddResource(Coscine.Database.Model.Project project, Resource resource)
{
if(project.ProjectResourceProjectIdIds.Any((pr) => pr.Resource == resource))
{
throw new InvalidOperationException("Resource is already assigned to project!");
}
ProjectResource projectResource = new ProjectResource();
projectResource.Project = project;
projectResource.Resource = resource;
project.ProjectResourceProjectIdIds.Append(projectResource);
Update(project);
}
public override Guid GetIdFromObject(Database.Model.Project databaseObject)
{
return databaseObject.Id;
}
public override ITable<Database.Model.Project> GetITableFromDatabase(CoscineDB db)
{
return db.Projects;
}
}
}
using Coscine.Database.Model;
using LinqToDB;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Models
{
public class ResourceModel : DatabaseModel<Resource>
{
public ResourceModel() : base(Program.Configurator.Configuration)
{
}
public bool OwnsResource(User user, Resource resource)
{
return DatabaseConnection.ConnectToDatabase((db) =>
{
return (from relation in db.ProjectRoles
where relation.User == user
&& relation.Role.DisplayName == "Owner"
&& relation.Project.ProjectResourceProjectIdIds.
Any((projectResource) => projectResource.Resource == resource)
select relation).Any();
});
}
public override Guid GetIdFromObject(Resource databaseObject)
{
return databaseObject.Id;
}
public override ITable<Resource> GetITableFromDatabase(CoscineDB db)
{
return db.Resources;
}
}
}
using Coscine.Database.Model;
using LinqToDB;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Coscine.Api.Project.Models
{
public class RoleModel : DatabaseModel<Role>
{
public RoleModel() : base(Program.Configurator.Configuration)
{
}
public override Guid GetIdFromObject(Role databaseObject)
{