Наследование: IWriteDocument
        public async Task<HttpResponseMessage> CreateTag(WriteDocument template)
        {
            //model state nao funciona aqui porque não existe [Required] no tipo WriteDocument
            if (IsTemplateIncorrect(template.Template))
            {
                return CollectionTemplateInvalidResponse();
            }

            var nameFromTemplate = template.Template.Data[0].Value;
            var projectNameFromTemplate = template.Template.Data[1].Value;

            nameFromTemplate = nameFromTemplate.Replace(" ", "-");
            var isTagPresent = await Context.Tags.AnyAsync(t => t.Name.Equals(nameFromTemplate));
            if (!isTagPresent)
            {
                Context.Tags.Add(new TagModel() { Name = nameFromTemplate });
            }
            var isTagRelatedToProject = await Context.ProjectTagSet.AnyAsync(p => p.TagName.Equals(nameFromTemplate));
            if (!isTagRelatedToProject)
            {
                Context.ProjectTagSet.Add(new ProjectTagSetModel
                {
                    ProjectName = projectNameFromTemplate,
                    TagName = nameFromTemplate
                });
            }
            else
            {
                return Request.BadRequestMessage(new List<ErrorResource.InvalidParams>
                {
                    new ErrorResource.InvalidParams
                    {
                        Name = template.Template.Data[0].Name,
                        Reason = $"A Tag with the name '{nameFromTemplate}' is already associated with the project '{projectNameFromTemplate}'."
                    }
                });
            }

            await Context.SaveChangesAsync();
            
            //build siren resource's representation to include in the response
            var dbRecord = await Context.Tags.FindAsync(nameFromTemplate);
            var resource = await BuildResource(projectNameFromTemplate, dbRecord.Name);

            var locationUri = MakeUri<ProjectsController>(c => c.FindSingleProject(nameFromTemplate));
            return Request.BuildCreatedResourceResponse(resource, locationUri);
        }
        public async Task<HttpResponseMessage> CreateIssue(string projectName, WriteDocument template)
        {
            var body = template.Template;
            if (IsTemplateIncorrect(body))
            {
                return CollectionTemplateInvalidResponse();
            }

            var projectRootEntity = await Context.Projects.FindAsync(projectName);
            if (projectRootEntity == null)
            {
                return Request.ResourceNotFoundMessage();
            }

            //BadRequest if state is not 'open' or 'closed'
            const int titleIdx = 0, stateIdx = 1, descriptionIdx = 2, tagsIdx = 3;
            if (!IsIssueStateValid(body.Data[stateIdx]?.Value))
            {
                return BadIssueStateErrorMessage(body, stateIdx);
            }

            int? lastElementIndex = Context.Issues.Max(i => (int?)i.Id); //used in the making of the URI

            //Tags must belong to the project's set
            if (template.Template.Data.Count > GetTemplateParams())
            {
                var tags = template.Template.Data[tagsIdx].Value.Split('+');
                var tagModels = tags.Select(tag => new TagModel {Name = tag}).ToList();
                //check if each tag is present in the ProjectTag set. if not, returns Error else associate it with the issue
                foreach (var tagModel in tagModels)
                {
                    //verificar existencia no project relativo a este issue
                    if (!await IsTagRelatedToProject(projectName, tagModel))
                    {
                        return TagNotRelatedToProjectError(body.Data[tagsIdx].Name);
                    }
                    //caso contrario, associa tag com issue
                    var elemIndex = (int)((lastElementIndex == null) ? 1 : lastElementIndex + 1);
                    AssociationBetweenTagAndIssue(tagModel, elemIndex);
                }
            }

            //what to save
            var newResource = new IssueModel
            {
                Title = body.Data[titleIdx].Value,
                State = body.Data[stateIdx].Value,
                Description = body.Data[descriptionIdx].Value,
                ProjectModel = projectRootEntity
            };
            Context.Issues.Add(newResource);

            Context.SaveChanges();

            var issueCreated = await BuildIssueResource(projectName, newResource);
            var locationUri = MakeUri<IssuesController>(c => c.GetSingleIssue(projectName, lastElementIndex.Value));
            return Request.BuildCreatedResourceResponse(issueCreated, locationUri);
        }
 private HttpResponseMessage ProcessNewProject(Template newProjTemplate)
 {
     var ctrler = new ProjectsController
     {
         Configuration = new HttpConfiguration(),
         Request = new HttpRequestMessage()
     };
     var dataFromBody = new WriteDocument { Template = newProjTemplate };
     return ctrler.CreateProject(dataFromBody).Result;
 }
    public async Task<HttpResponseMessage> CreateComment(string projectName, int issueId, WriteDocument template)
    {
      //assert template
      if (IsTemplateIncorrect(template.Template))
      {
        return CollectionTemplateInvalidResponse();
      }
      //assert association between project and issue
      if (!await IsIssueRelatedToProject(projectName, issueId))
      {
        return Request.ResourceNotFoundMessage();
      }
      //assert issue is not "closed"
      var issue =
        await Context.Issues.SingleOrDefaultAsync(i => i.ProjectModel.Name.Equals(projectName) && i.Id == issueId);
      if (issue.State.Equals(IssuesController.ClosedState))
      {
        var details = "A closed issue does not accept comments.";
        return Request.BadRequestMessage(null, details);
      }

      var contentOfComment = template.Template.Data[0].Value;
      var project = await Context.Projects.FindAsync(projectName);
      Context.Comments.Add(new CommentModel
      {
        Content = contentOfComment,
        ProjectModel = project,
        IssueModel = issue
      });
      await Context.SaveChangesAsync();

      // build the (siren) resource
      var lastIndex = Context.Comments.Where(c => c.IssueModel.Id == issueId).Max(i => (int?) i.Id);
      var model = await Context
        .Comments.SingleOrDefaultAsync(c => c.Id == lastIndex.Value
                                            && c.IssueModel.Id == issueId
                                            && c.ProjectModel.Name.Equals(projectName));

      var resource = BuildCommentResource(projectName, issueId, model);
      var selfLink = MakeUri<CommentsController>(c => c.GetSingleComment(projectName, issueId, model.Id));
      return Request.BuildCreatedResourceResponse(resource, selfLink);
    }
        public async Task<HttpResponseMessage> CreateProject(WriteDocument template)
        {
            //model state nao funciona aqui porque não tenho [Required] no tipo WriteDocument
            if (IsTemplateIncorrect(template.Template))
            {
                return CollectionTemplateInvalidResponse();
            }

            const int projectNameIdx = 0;

            var projectName = template.Template.Data[projectNameIdx].Value ;
            if (projectName == null)
            {
                return CollectionTemplateInvalidResponse();
            }
            projectName = projectName.Replace(" ", "-");

            var existsProject = await Context.Projects.AnyAsync(p => p.Name.Equals(projectName));
            if (existsProject)
            {
                return Request.BadRequestMessage(new List<ErrorResource.InvalidParams>
                {
                    new ErrorResource.InvalidParams
                    {
                        Name = template.Template.Data[projectNameIdx].Name,
                        Reason = $"A project with the name '{projectName}' already exists."
                    }
                });
            }

            if (! await SaveNewProject(template, projectName))
            {
                return CollectionTemplateInvalidResponse();
            }

            //build siren resource's representation
            var dbRecord = await Context.Projects.FindAsync(projectName);
            var resource = await BuildProjectResource(dbRecord.Id.ToString(), dbRecord.Name);

            //send 201, representation and location of the new resource
            var locationUri = MakeUri<ProjectsController>(c => c.FindSingleProject(projectName));
            return Request.BuildCreatedResourceResponse(resource, locationUri);
        }