From ae5ddfa544d6e576d211c2414a3fe9f1e53986bc Mon Sep 17 00:00:00 2001
From: David Schimmel <schimmel@itc.rwth-aachen.de>
Date: Tue, 23 Jul 2019 14:52:23 +0200
Subject: [PATCH] add subsite creation (coscine/issues#180)

---
 src/Project.Tests/ProjectControllerTests.cs   | 64 +++++++++++++++++++
 src/Project/Controllers/ProjectController.cs  |  8 +++
 .../Features/Feature1/Feature1.Template.xml   |  3 +
 .../css/remove-sharepoint-controls.css        | 14 ++++
 src/Project/Models/SubProjectModel.cs         | 45 +++++++++++++
 src/Project/Project.csproj                    |  7 ++
 src/Project/ReturnObjects/ProjectObject.cs    |  6 +-
 src/Project/VueComponent/Elements.xml         |  8 +++
 .../VueComponent/VueComponentUserControl.ascx | 15 +++++
 9 files changed, 168 insertions(+), 2 deletions(-)
 create mode 100644 src/Project/Features/Feature1/Feature1.Template.xml
 create mode 100644 src/Project/Layouts/Coscine.SharePoint.Webparts.Vue/css/remove-sharepoint-controls.css
 create mode 100644 src/Project/Models/SubProjectModel.cs
 create mode 100644 src/Project/VueComponent/Elements.xml
 create mode 100644 src/Project/VueComponent/VueComponentUserControl.ascx

diff --git a/src/Project.Tests/ProjectControllerTests.cs b/src/Project.Tests/ProjectControllerTests.cs
index 1b5f2be..f5966ab 100644
--- a/src/Project.Tests/ProjectControllerTests.cs
+++ b/src/Project.Tests/ProjectControllerTests.cs
@@ -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()
         {
diff --git a/src/Project/Controllers/ProjectController.cs b/src/Project/Controllers/ProjectController.cs
index c089ece..7623479 100644
--- a/src/Project/Controllers/ProjectController.cs
+++ b/src/Project/Controllers/ProjectController.cs
@@ -83,6 +83,14 @@ namespace Coscine.Api.Project.Controllers
                 ProjectModel projectModel = new ProjectModel();
                 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));
 
                 return new ProjectObject(project.Id, project.Description, project.DisplayName, project.Organization, project.StartDate, project.EndDate, project.Keywords);
diff --git a/src/Project/Features/Feature1/Feature1.Template.xml b/src/Project/Features/Feature1/Feature1.Template.xml
new file mode 100644
index 0000000..c27273d
--- /dev/null
+++ b/src/Project/Features/Feature1/Feature1.Template.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<Feature xmlns="http://schemas.microsoft.com/sharepoint/">
+</Feature>
\ No newline at end of file
diff --git a/src/Project/Layouts/Coscine.SharePoint.Webparts.Vue/css/remove-sharepoint-controls.css b/src/Project/Layouts/Coscine.SharePoint.Webparts.Vue/css/remove-sharepoint-controls.css
new file mode 100644
index 0000000..0069f11
--- /dev/null
+++ b/src/Project/Layouts/Coscine.SharePoint.Webparts.Vue/css/remove-sharepoint-controls.css
@@ -0,0 +1,14 @@
+.ms-breadcrumb-top,
+#SearchBox,
+#suiteBarButtons,
+#globalNavBox {
+  display: none !important;
+}
+
+#welcomeMenuBox {
+  margin-top: 5px;
+}
+
+body.rwth-seattle #s4-titlerow, .ms-breadcrumb-box {
+  height: auto !important;
+}
diff --git a/src/Project/Models/SubProjectModel.cs b/src/Project/Models/SubProjectModel.cs
new file mode 100644
index 0000000..b0d67e9
--- /dev/null
+++ b/src/Project/Models/SubProjectModel.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using Coscine.Api.Project.ReturnObjects;
+using Coscine.ApiCommons.Models;
+using Coscine.Database.Model;
+using LinqToDB;
+
+namespace Coscine.Api.Project.Models
+{
+    public class SubProjectModel : DatabaseModel<Coscine.Database.Model.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)
+        {
+            Coscine.Database.Model.SubProject subProject = new Coscine.Database.Model.SubProject()
+            {
+                ProjectId = parentId,
+                SubProjectId = childId,
+            };
+            Insert(subProject);
+            return;
+        }
+
+        public override void SetObjectId(SubProject databaseObject, Guid id)
+        {
+            databaseObject.RelationId = id;
+        }
+    }
+}
diff --git a/src/Project/Project.csproj b/src/Project/Project.csproj
index d8877e0..863a64f 100644
--- a/src/Project/Project.csproj
+++ b/src/Project/Project.csproj
@@ -572,6 +572,7 @@
     <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" />
@@ -587,6 +588,12 @@
   <ItemGroup>
     <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
   </ItemGroup>
+  <ItemGroup>
+    <Content Include="Features\Feature1\Feature1.Template.xml" />
+    <Content Include="Layouts\Coscine.SharePoint.Webparts.Vue\css\remove-sharepoint-controls.css" />
+    <Content Include="VueComponent\Elements.xml" />
+    <Content Include="VueComponent\VueComponentUserControl.ascx" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
     <PropertyGroup>
diff --git a/src/Project/ReturnObjects/ProjectObject.cs b/src/Project/ReturnObjects/ProjectObject.cs
index f769fb1..6094df6 100644
--- a/src/Project/ReturnObjects/ProjectObject.cs
+++ b/src/Project/ReturnObjects/ProjectObject.cs
@@ -16,7 +16,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 +27,7 @@ namespace Coscine.Api.Project.ReturnObjects
             StartDate = startDate;
             EndDate = endDate;
             Keywords = keywords;
+            ParentId = parentId;
         }
-
     }
 }
diff --git a/src/Project/VueComponent/Elements.xml b/src/Project/VueComponent/Elements.xml
new file mode 100644
index 0000000..9cb73fa
--- /dev/null
+++ b/src/Project/VueComponent/Elements.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Elements xmlns="http://schemas.microsoft.com/sharepoint/" >
+  <Module Name="VueComponent" List="113" Url="_catalogs/wp">
+    <File Path="VueComponent\VueComponent.webpart" Url="Coscine.SharePoint.Webparts.Vue_VueComponent.webpart" Type="GhostableInLibrary" >
+      <Property Name="Group" Value="Custom" />
+    </File>
+  </Module>
+</Elements>
diff --git a/src/Project/VueComponent/VueComponentUserControl.ascx b/src/Project/VueComponent/VueComponentUserControl.ascx
new file mode 100644
index 0000000..2a98b4d
--- /dev/null
+++ b/src/Project/VueComponent/VueComponentUserControl.ascx
@@ -0,0 +1,15 @@
+<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
+<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
+<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
+<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
+<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
+<%@ Import Namespace="Microsoft.SharePoint" %> 
+<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
+<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="VueComponentUserControl.ascx.cs" Inherits="Coscine.SharePoint.Webparts.Vue.VueComponent.VueComponentUserControl" %>
+
+<script type="text/javascript">
+    var coscine = coscine || {};
+    coscine.authorization = coscine.authorization || {};
+    coscine.authorization.bearer = "<%= GetUserJWT() %>";
+    window.component = "<%= GetComponent() %>";
+</script>
\ No newline at end of file
-- 
GitLab