public async Task <IActionResult> SubmitPost(Submission sub, Guid id, string stage, IEnumerable <IFormFile> uploadFiles) { if (ModelState.IsValid) { var asg = await _context.Assignments .Include(a => a.Stages) .Include(a => a.Course) .Include(a => a.Groups) .ThenInclude(g => g.Members) .ThenInclude(gjt => gjt.ApplicationUser) .SingleOrDefaultAsync(a => a.ID == id); var astage = asg.Stages.SingleOrDefault(stg => stg.Id == stage); var user = await _userManager.GetUserAsync(User); var group = asg.GroupFor(user); if (group != null) { _context.Entry(group).Collection(g => g.Members).Load(); } var presub = await _context.Submissions .Include(s => s.AssignmentStage) .Include(s => s.Submitter) .Include(s => s.ForGroup) .SingleOrDefaultAsync(s => s.AssignmentStage == astage && (s.Submitter.Id == user.Id || (group != null && s.ForGroup.ID == group.ID))); if (astage == null || presub != null) { return(NotFound()); } var filerefs = new List <FileRef>(); foreach (IFormFile f in uploadFiles) { var fileref = new FileRef { ID = Guid.NewGuid(), Owner = user, Name = f.FileName, ContentType = f.ContentType, }; using (var stream = fileref.Open(_config["Storage:BasePath"], FileMode.Create)) { await f.CopyToAsync(stream); } await _context.FileRefs.AddAsync(fileref); filerefs.Add(fileref); } sub.Submitter = user; sub.ForGroup = group; // TODO: change to allow students to modify their submissions sub.Confirmed = true; sub.AssignmentStage = astage; sub.ID = Guid.NewGuid(); sub.Files = filerefs; sub.TimeStamp = DateTime.Now; if (group == null) { var _stageHolder = await _context.StageHolders .SingleOrDefaultAsync(sh => sh.AssignmentID == asg.ID && sh.UserID == user.Id); if (_stageHolder != null) { _stageHolder.CurrentStage += 1; _context.Update(_stageHolder); } else { var newSH = new StageHolder { AssignmentID = asg.ID, UserID = user.Id, CurrentStage = Assignment.START_STAGE + 1, }; _context.Add(newSH); } } else { group.CurrentStage += 1; _context.Update(group); } await _context.AddAsync(sub); // Feels wrong to await this. It should be a continuation of some kind that // doesn't need to be performed on this thread. Possibly Save Changes and // start an assignment pass if (astage.IsPeerReviewed) { await ReviewPass(sub, astage.ReviewsPerStudent); } await _context.SaveChangesAsync(); return(RedirectToAction(nameof(StudentDetails), new { id = asg.ID })); } else { ViewData["Error"] = string.Join("; ", ModelState.Values.Select(v => v.Errors)); ViewData["AssignmentID"] = id; ViewData["StageID"] = stage; return(View(sub)); } }