diff --git a/Open Judge System/Data/OJS.Data.Models/Submission.cs b/Open Judge System/Data/OJS.Data.Models/Submission.cs index 2d82ac6d03..f70a85e4f9 100644 --- a/Open Judge System/Data/OJS.Data.Models/Submission.cs +++ b/Open Judge System/Data/OJS.Data.Models/Submission.cs @@ -45,7 +45,7 @@ public Submission() public string FileExtension { get; set; } [StringLength(45)] - [Column(TypeName="varchar")] + [Column(TypeName = "varchar")] public string IpAddress { get; set; } [NotMapped] diff --git a/Open Judge System/Data/OJS.Data.Models/UserProfile.cs b/Open Judge System/Data/OJS.Data.Models/UserProfile.cs index 81684183c9..0164bd1b5a 100644 --- a/Open Judge System/Data/OJS.Data.Models/UserProfile.cs +++ b/Open Judge System/Data/OJS.Data.Models/UserProfile.cs @@ -7,6 +7,7 @@ using Microsoft.AspNet.Identity.EntityFramework; + using OJS.Common; using OJS.Data.Contracts; using OJS.Data.Contracts.DataAnnotations; @@ -26,7 +27,9 @@ public UserProfile(string userName, string email) } [Required] - [MaxLength(80)] + [MaxLength(GlobalConstants.EmailMaxLength)] + [MinLength(GlobalConstants.EmailMinLength)] + [RegularExpression(GlobalConstants.EmailRegEx)] [IsUnicode(false)] [DataType(DataType.EmailAddress)] public string Email { get; set; } diff --git a/Open Judge System/Data/OJS.Data.Models/UserSettings.cs b/Open Judge System/Data/OJS.Data.Models/UserSettings.cs index 253d30f581..6f15d7dfab 100644 --- a/Open Judge System/Data/OJS.Data.Models/UserSettings.cs +++ b/Open Judge System/Data/OJS.Data.Models/UserSettings.cs @@ -15,19 +15,22 @@ public UserSettings() } [Column("FirstName")] - [MaxLength(30)] + [MinLength(GlobalConstants.NameMinLength)] + [MaxLength(GlobalConstants.NameMaxLength)] public string FirstName { get; set; } [Column("LastName")] - [MaxLength(30)] + [MinLength(GlobalConstants.NameMinLength)] + [MaxLength(GlobalConstants.NameMaxLength)] public string LastName { get; set; } [Column("City")] - [MaxLength(30)] + [MinLength(GlobalConstants.CityMinLength)] + [MaxLength(GlobalConstants.CityMaxLength)] + [RegularExpression(GlobalConstants.CityRegEx)] public string City { get; set; } [Column("EducationalInstitution")] - [MaxLength(50)] public string EducationalInstitution { get; set; } [Column("FacultyNumber")] @@ -40,11 +43,15 @@ public UserSettings() public DateTime? DateOfBirth { get; set; } [Column("Company")] - [MaxLength(30)] + [MaxLength(GlobalConstants.CompanyMaxLength)] + [MinLength(GlobalConstants.CompanyMinLength)] + [RegularExpression(GlobalConstants.CompanyRegEx)] public string Company { get; set; } [Column("JobTitle")] - [MaxLength(30)] + [MaxLength(GlobalConstants.JobTitleMaxLength)] + [MinLength(GlobalConstants.JobTitleMinLength)] + [RegularExpression(GlobalConstants.JobTitleRegEx)] public string JobTitle { get; set; } [NotMapped] diff --git a/Open Judge System/Data/OJS.Data/OjsDbContext.cs b/Open Judge System/Data/OJS.Data/OjsDbContext.cs index ea214d4ea8..ff9d2d0c23 100644 --- a/Open Judge System/Data/OJS.Data/OjsDbContext.cs +++ b/Open Judge System/Data/OJS.Data/OjsDbContext.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; using System.Data.Entity; + using System.Data.Entity.Validation; + using System.Diagnostics; using System.Linq; using Microsoft.AspNet.Identity.EntityFramework; @@ -72,6 +74,23 @@ public override int SaveChanges() { this.ApplyAuditInfoRules(); this.ApplyDeletableEntityRules(); + + ////// Use this to see Database validation errors + ////try + ////{ + //// return base.SaveChanges(); + ////} + ////catch (DbEntityValidationException databeseException) + ////{ + //// foreach (var validationErrors in databeseException.EntityValidationErrors) + //// { + //// foreach (var validationError in validationErrors.ValidationErrors) + //// { + //// Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage); + //// } + //// } + ////} + return base.SaveChanges(); } diff --git a/Open Judge System/Data/OJS.Data/Repositories/Contracts/ISubmissionsRepository.cs b/Open Judge System/Data/OJS.Data/Repositories/Contracts/ISubmissionsRepository.cs index fc5f41dd4c..e19709e5e8 100644 --- a/Open Judge System/Data/OJS.Data/Repositories/Contracts/ISubmissionsRepository.cs +++ b/Open Judge System/Data/OJS.Data/Repositories/Contracts/ISubmissionsRepository.cs @@ -1,10 +1,11 @@ namespace OJS.Data.Repositories.Contracts { using System.Linq; + using OJS.Data.Contracts; using OJS.Data.Models; - public interface ISubmissionsRepository : IRepository, IDeletableEntityRepository + public interface ISubmissionsRepository : IDeletableEntityRepository { IQueryable AllPublic(); diff --git a/Open Judge System/OJS.Common/Extensions/ExecutionStrategyTypeExtensions.cs b/Open Judge System/OJS.Common/Extensions/ExecutionStrategyTypeExtensions.cs index b85b0b85ea..c8b847551b 100644 --- a/Open Judge System/OJS.Common/Extensions/ExecutionStrategyTypeExtensions.cs +++ b/Open Judge System/OJS.Common/Extensions/ExecutionStrategyTypeExtensions.cs @@ -1,7 +1,5 @@ namespace OJS.Common.Extensions { - using System; - using OJS.Common.Models; public static class ExecutionStrategyTypeExtensions @@ -14,6 +12,8 @@ public static string GetFileExtension(this ExecutionStrategyType executionStrate return null; // The file extension depends on the compiler. case ExecutionStrategyType.NodeJsPreprocessExecuteAndCheck: return "js"; + case ExecutionStrategyType.JavaPreprocessCompileExecuteAndCheck: + return "java"; default: return null; } diff --git a/Open Judge System/OJS.Common/Extensions/StringExtensions.cs b/Open Judge System/OJS.Common/Extensions/StringExtensions.cs index 50f5f9f2b7..de7286c034 100644 --- a/Open Judge System/OJS.Common/Extensions/StringExtensions.cs +++ b/Open Judge System/OJS.Common/Extensions/StringExtensions.cs @@ -185,19 +185,19 @@ public static string PascalCaseToText(this string input) { char symbolToAdd = input[i]; - if (Char.IsUpper(symbolToAdd) && previous == WhiteSpace && !inWord) + if (char.IsUpper(symbolToAdd) && previous == WhiteSpace && !inWord) { inWord = true; isAbbreviation = true; abbreviation.Append(symbolToAdd); } - else if (Char.IsUpper(symbolToAdd) && inWord) + else if (char.IsUpper(symbolToAdd) && inWord) { abbreviation.Append(symbolToAdd); currentWord.Append(WhiteSpace); - symbolToAdd = Char.ToLower(symbolToAdd); + symbolToAdd = char.ToLower(symbolToAdd); } - else if (Char.IsLower(symbolToAdd) && inWord) + else if (char.IsLower(symbolToAdd) && inWord) { isAbbreviation = false; } diff --git a/Open Judge System/OJS.Common/GlobalConstants.cs b/Open Judge System/OJS.Common/GlobalConstants.cs index 62746ef44d..98ba63a193 100644 --- a/Open Judge System/OJS.Common/GlobalConstants.cs +++ b/Open Judge System/OJS.Common/GlobalConstants.cs @@ -2,6 +2,36 @@ { public static class GlobalConstants { + #region User Profile Constants + + public const int UsernameMinLength = 5; + public const int UsernameMaxLength = 32; + public const string UsernameRegEx = @"^[a-zA-Z]([/._]?[a-zA-Z0-9]+)+$"; + + public const int PasswordMinLength = 6; + public const int PasswordMaxLength = 1000; + + public const int EmailMaxLength = 80; + public const int EmailMinLength = 6; + public const string EmailRegEx = "^[A-Za-z0-9]+[\\._A-Za-z0-9-]+@([A-Za-z0-9]+[-\\.]?[A-Za-z0-9]+)+(\\.[A-Za-z0-9]+[-\\.]?[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; + + public const int NameMinLength = 2; + public const int NameMaxLength = 30; + + public const int CityMinLength = 3; + public const int CityMaxLength = 50; + public const string CityRegEx = @"^[a-zA-Zа-яА-Я]+(?:[\s-][a-zA-Zа-яА-Я]+)*$"; + + public const int CompanyMinLength = 2; + public const int CompanyMaxLength = 100; + public const string CompanyRegEx = @"^([a-zA-Zа-яА-Я0-9]|[- @\.#&!""])*$"; + + public const int JobTitleMinLength = 2; + public const int JobTitleMaxLength = 100; + public const string JobTitleRegEx = @"^([a-zA-Zа-яА-Я0-9]|[- @\.#&!])*$"; + + #endregion + #region TempData dictionary keys public const string InfoMessage = "InfoMessage"; diff --git a/Open Judge System/OJS.Common/MailSender.cs b/Open Judge System/OJS.Common/MailSender.cs index c94bad736f..1d6d9a4523 100644 --- a/Open Judge System/OJS.Common/MailSender.cs +++ b/Open Judge System/OJS.Common/MailSender.cs @@ -10,10 +10,12 @@ public sealed class MailSender // TODO: Extract user, address and password as app.config settings private const string SendFrom = "bgcoder.com@gmail.com"; private const string SendFromName = "BGCoder.com"; - private const string Password = "__YOUR_PASSWORD_HERE__"; - private const string ServerAddress = "smtp.gmail.com"; - private const int ServerPort = 587; + private const string SmtpUsername = "SMTPUser"; + private const string Password = "M@1L^unRestricteD!"; + + private const string ServerAddress = "smtp.softuni.bg"; + private const int ServerPort = 25; private static readonly object SyncRoot = new object(); @@ -22,14 +24,15 @@ public sealed class MailSender private MailSender() { - //// this.mailClient = new SmtpClient - //// { - //// Credentials = new NetworkCredential(SendFrom, Password), - //// Port = ServerPort, - //// Host = ServerAddress, - //// EnableSsl = true, - //// }; - this.mailClient = new SmtpClient { DeliveryMethod = SmtpDeliveryMethod.PickupDirectoryFromIis }; + this.mailClient = new SmtpClient + { + Credentials = new NetworkCredential(SmtpUsername, Password), + Port = ServerPort, + Host = ServerAddress, + EnableSsl = true, + }; + + ////this.mailClient = new SmtpClient { DeliveryMethod = SmtpDeliveryMethod.PickupDirectoryFromIis }; } public static MailSender Instance @@ -44,7 +47,7 @@ public static MailSender Instance { instance = new MailSender(); } - } + } } return instance; diff --git a/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.bg.resx b/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.bg.resx index 6f4e185b73..879b1cb912 100644 --- a/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.bg.resx +++ b/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.bg.resx @@ -148,10 +148,10 @@ Предишни състезания - Онлайн задачи по програмиране + - BGCoder + SoftUni Judge Оставащо време: {0} {1} и {2} минути diff --git a/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.designer.cs b/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.designer.cs index 57144b0ceb..5ffcb82ffc 100644 --- a/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.designer.cs +++ b/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.18408 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -151,7 +151,7 @@ public static string Previous_contests { } /// - /// Looks up a localized string similar to Solve programming problems online. + /// Looks up a localized string similar to . /// public static string Project_subtitle { get { @@ -160,7 +160,7 @@ public static string Project_subtitle { } /// - /// Looks up a localized string similar to BGCoder. + /// Looks up a localized string similar to SoftUni Judge. /// public static string Project_title { get { diff --git a/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.resx b/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.resx index 616858e776..d62b783ae4 100644 --- a/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.resx +++ b/Open Judge System/Web/OJS.Web/App_GlobalResources/Home/Views/Index.resx @@ -148,10 +148,10 @@ Previous contests - Solve programming problems online + - BGCoder + SoftUni Judge Time remaining: {0} {1} and {2} minutes diff --git a/Open Judge System/Web/OJS.Web/App_Start/BundleConfig.cs b/Open Judge System/Web/OJS.Web/App_Start/BundleConfig.cs index f7659d3829..bddfe5cd15 100644 --- a/Open Judge System/Web/OJS.Web/App_Start/BundleConfig.cs +++ b/Open Judge System/Web/OJS.Web/App_Start/BundleConfig.cs @@ -51,10 +51,10 @@ private static void RegisterStyles(BundleCollection bundles) bundles.Add(new StyleBundle("~/Content/KendoUI/kendo").Include( "~/Content/KendoUI/kendo.common.css", - "~/Content/KendoUI/kendo.black.css")); + "~/Content/KendoUI/kendo.blueopal.min.css")); bundles.Add(new StyleBundle("~/Content/bootstrap/bootstrap").Include( - "~/Content/bootstrap/themes/bootstrap-theme-cyborg.css")); + "~/Content/bootstrap/bootstrap-flatly.css")); bundles.Add(new StyleBundle("~/Content/CodeMirror/codemirror").Include( "~/Content/CodeMirror/codemirror.css", diff --git a/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/ProblemsController.cs b/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/ProblemsController.cs index dd933986f3..775ba9f902 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/ProblemsController.cs +++ b/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/ProblemsController.cs @@ -86,7 +86,7 @@ public ActionResult Create(int? id) var lastOrderBy = -1; var lastProblem = this.Data.Problems.All().Where(x => x.ContestId == id); - if (lastProblem.Count() > 0) + if (lastProblem.Any()) { lastOrderBy = lastProblem.Max(x => x.OrderBy); } @@ -97,11 +97,12 @@ public ActionResult Create(int? id) MaximumPoints = 100, TimeLimit = 100, MemoryLimit = 16777216, - AvailableCheckers = this.Data.Checkers.All().Select(checker => new SelectListItem { Text = checker.Name, Value = checker.Name }), + AvailableCheckers = this.Data.Checkers.All().Select(checker => new SelectListItem { Text = checker.Name, Value = checker.Name, Selected = checker.Name.Contains("Trim") }), OrderBy = lastOrderBy + 1, ContestId = contest.Id, ContestName = contest.Name, ShowResults = true, + SourceCodeSizeLimit = 16384, }; return this.View(problem); @@ -111,7 +112,7 @@ public ActionResult Create(int? id) [ValidateAntiForgeryToken] public ActionResult Create(int id, HttpPostedFileBase testArchive, DetailedProblemViewModel problem) { - if (problem.Resources != null && problem.Resources.Count() > 0) + if (problem.Resources != null && problem.Resources.Any()) { var validResources = problem.Resources .All(res => !string.IsNullOrEmpty(res.Name) && @@ -137,10 +138,10 @@ public ActionResult Create(int id, HttpPostedFileBase testArchive, DetailedProbl SourceCodeSizeLimit = problem.SourceCodeSizeLimit, ShowResults = problem.ShowResults, OrderBy = problem.OrderBy, - Checker = this.Data.Checkers.All().Where(x => x.Name == problem.Checker).FirstOrDefault() + Checker = this.Data.Checkers.All().FirstOrDefault(x => x.Name == problem.Checker) }; - if (problem.Resources != null && problem.Resources.Count() > 0) + if (problem.Resources != null && problem.Resources.Any()) { this.AddResourcesToProblem(newProblem, problem.Resources); } @@ -199,8 +200,8 @@ public ActionResult Edit(int? id) Name = problem.Name, ContestId = problem.ContestId, ContestName = problem.Contest.Name, - TrialTests = problem.Tests.AsQueryable().Where(x => x.IsTrialTest).Count(), - CompeteTests = problem.Tests.AsQueryable().Where(x => !x.IsTrialTest).Count(), + TrialTests = problem.Tests.AsQueryable().Count(x => x.IsTrialTest), + CompeteTests = problem.Tests.AsQueryable().Count(x => !x.IsTrialTest), MaximumPoints = problem.MaximumPoints, TimeLimit = problem.TimeLimit, MemoryLimit = problem.MemoryLimit, @@ -272,8 +273,8 @@ public ActionResult Delete(int? id) Name = problem.Name, ContestId = problem.ContestId, ContestName = problem.Contest.Name, - TrialTests = problem.Tests.AsQueryable().Where(x => x.IsTrialTest).Count(), - CompeteTests = problem.Tests.AsQueryable().Where(x => !x.IsTrialTest).Count(), + TrialTests = problem.Tests.AsQueryable().Count(x => x.IsTrialTest), + CompeteTests = problem.Tests.AsQueryable().Count(x => !x.IsTrialTest), MaximumPoints = problem.MaximumPoints, TimeLimit = problem.TimeLimit, MemoryLimit = problem.MemoryLimit, diff --git a/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/SubmissionsController.cs b/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/SubmissionsController.cs index 577a8399e1..623d1f4f5e 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/SubmissionsController.cs +++ b/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/SubmissionsController.cs @@ -149,7 +149,7 @@ public ActionResult Update(ModelType model) } } - if (model != null && this.ModelState.IsValid) + if (this.ModelState.IsValid) { if (model.ProblemId.HasValue) { diff --git a/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/TestsController.cs b/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/TestsController.cs index 7e986fdbad..692f80ad99 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/TestsController.cs +++ b/Open Judge System/Web/OJS.Web/Areas/Administration/Controllers/TestsController.cs @@ -163,10 +163,7 @@ public ActionResult Edit(int id, TestViewModel test) { if (test != null && this.ModelState.IsValid) { - var existingTest = this.Data.Tests - .All() - .FirstOrDefault(t => t.Id == id); - + var existingTest = this.Data.Tests.GetById(id); if (existingTest == null) { this.TempData[GlobalConstants.DangerMessage] = "Невалиден тест"; @@ -604,7 +601,7 @@ public ActionResult Import(string problemId, HttpPostedFileBase file, bool retes /// Zip file containing all tests in format {task}.{testNum}[.{zeroNum}].{in|out}.txt public ActionResult Export(int id) { - var problem = this.Data.Problems.All().Where(x => x.Id == id).FirstOrDefault(); + var problem = this.Data.Problems.All().FirstOrDefault(x => x.Id == id); if (problem == null) { @@ -654,7 +651,8 @@ public FileResult ExportToExcel([DataSourceRequest] DataSourceRequest request, i private IEnumerable GetData(int id) { - var result = this.Data.Tests.All() + var result = this.Data.Tests + .All() .Where(test => test.ProblemId == id) .OrderByDescending(test => test.IsTrialTest) .ThenBy(test => test.OrderBy) @@ -665,10 +663,10 @@ private IEnumerable GetData(int id) private void RetestSubmissions(Problem problem) { - var submissionIds = problem.Submissions.Select(s => new { Id = s.Id }).ToList(); + var submissionIds = problem.Submissions.Select(s => s.Id).ToList(); foreach (var submissionId in submissionIds) { - var currentSubmission = this.Data.Submissions.GetById(submissionId.Id); + var currentSubmission = this.Data.Submissions.GetById(submissionId); currentSubmission.Processed = false; currentSubmission.Processing = false; } diff --git a/Open Judge System/Web/OJS.Web/Areas/Administration/ViewModels/Test/TestViewModel.cs b/Open Judge System/Web/OJS.Web/Areas/Administration/ViewModels/Test/TestViewModel.cs index a4a6d2fefd..207a241f56 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Administration/ViewModels/Test/TestViewModel.cs +++ b/Open Judge System/Web/OJS.Web/Areas/Administration/ViewModels/Test/TestViewModel.cs @@ -37,8 +37,8 @@ public static Expression> FromTest public string ProblemName { get; set; } [Display(Name = "Вход")] - [AllowHtml] [DataType(DataType.MultilineText)] + [AllowHtml] [Required(ErrorMessage = "Входа е задължителен!", AllowEmptyStrings = false)] [StringLength(int.MaxValue, MinimumLength = 1)] public string Input @@ -61,8 +61,8 @@ public string Input } [Display(Name = "Вход")] - [AllowHtml] [DataType(DataType.MultilineText)] + [AllowHtml] [Required(ErrorMessage = "Входа е задължителен!", AllowEmptyStrings = false)] [ScriptIgnore] [StringLength(int.MaxValue, MinimumLength = 1)] @@ -86,8 +86,8 @@ public string InputFull } [Display(Name = "Изход")] - [AllowHtml] [DataType(DataType.MultilineText)] + [AllowHtml] [Required(ErrorMessage = "Изхода е задължителен!", AllowEmptyStrings = false)] [StringLength(int.MaxValue, MinimumLength = 1)] public string Output @@ -110,8 +110,8 @@ public string Output } [Display(Name = "Изход")] - [AllowHtml] [DataType(DataType.MultilineText)] + [AllowHtml] [Required(ErrorMessage = "Изхода е задължителен!", AllowEmptyStrings = false)] [ScriptIgnore] [StringLength(int.MaxValue, MinimumLength = 1)] diff --git a/Open Judge System/Web/OJS.Web/Areas/Administration/Views/Problems/Create.cshtml b/Open Judge System/Web/OJS.Web/Areas/Administration/Views/Problems/Create.cshtml index 5fca7db369..763cd5d0e1 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Administration/Views/Problems/Create.cshtml +++ b/Open Judge System/Web/OJS.Web/Areas/Administration/Views/Problems/Create.cshtml @@ -101,7 +101,7 @@
- + Да @(Html.Kendo() .NumericTextBoxFor(m => m.SourceCodeSizeLimit) diff --git a/Open Judge System/Web/OJS.Web/Areas/Api/Controllers/ResultsController.cs b/Open Judge System/Web/OJS.Web/Areas/Api/Controllers/ResultsController.cs index c7b4359c0f..54ef30a199 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Api/Controllers/ResultsController.cs +++ b/Open Judge System/Web/OJS.Web/Areas/Api/Controllers/ResultsController.cs @@ -1,5 +1,6 @@ namespace OJS.Web.Areas.Api.Controllers { + using System.Data.Entity; using System.Globalization; using System.Linq; using System.Web.Mvc; @@ -108,25 +109,73 @@ public JsonResult GetAllResultsForContest(string apiKey, int? contestId) return this.Json(new ErrorMessageViewModel("Invalid API key"), JsonRequestBehavior.AllowGet); } - var participants = - this.Data.Participants.All() - .Where(x => x.IsOfficial && x.ContestId == contestId.Value) - .Select( - participant => - new - { - participant.User.UserName, - participant.User.Email, - Answer = participant.Answers.Select(answer => answer.Answer).FirstOrDefault(), - Points = participant.Contest.Problems.Select( - problem => - problem.Submissions.Where(z => z.ParticipantId == participant.Id) - .OrderByDescending(z => z.Points) - .Select(z => z.Points) - .FirstOrDefault()).Sum() - }) - .OrderByDescending(x => x.Points) - .ToList(); + var participants = this.Data.Participants + .All() + .Where(x => x.IsOfficial && x.ContestId == contestId.Value) + .Select(participant => + new + { + participant.User.UserName, + participant.User.Email, + Answer = participant.Answers.Select(answer => answer.Answer).FirstOrDefault(), + Points = participant.Contest.Problems + .Select(problem => problem.Submissions + .Where(z => z.ParticipantId == participant.Id) + .OrderByDescending(z => z.Points) + .Select(z => z.Points) + .FirstOrDefault()) + .Sum(), + Minutes = participant.Submissions + .OrderByDescending(x => x.CreatedOn) + .Select(x => DbFunctions.DiffMinutes(participant.Contest.StartTime, x.CreatedOn)) + .FirstOrDefault() + }) + .OrderByDescending(x => x.Points) + .ThenBy(x => x.Minutes) + .ThenBy(x => x.UserName) + .ToList(); + + return this.Json(participants, JsonRequestBehavior.AllowGet); + } + + public JsonResult GetAllResultsForContestWithPoints(string apiKey, int? contestId) + { + if (string.IsNullOrWhiteSpace(apiKey) || !contestId.HasValue) + { + return this.Json(new ErrorMessageViewModel("Invalid arguments"), JsonRequestBehavior.AllowGet); + } + + var user = this.Data.Users.GetById(apiKey); + if (user == null || user.Roles.All(x => x.Role.Name != GlobalConstants.AdministratorRoleName)) + { + return this.Json(new ErrorMessageViewModel("Invalid API key"), JsonRequestBehavior.AllowGet); + } + + var participants = this.Data.Participants + .All() + .Where(x => x.IsOfficial && x.ContestId == contestId.Value) + .Select(participant => + new + { + participant.User.UserName, + participant.User.Email, + Answer = participant.Answers.Select(answer => answer.Answer).FirstOrDefault(), + Points = participant.Contest.Problems + .Select(problem => problem.Submissions + .Where(z => z.ParticipantId == participant.Id) + .OrderByDescending(z => z.Points) + .Select(z => z.Points) + .FirstOrDefault()) + .Sum(), + ExamTimeInMinutes = participant.Submissions + .Where(x => x.Problem.ContestId == contestId.Value) + .OrderByDescending(x => x.CreatedOn) + .Select(x => DbFunctions.DiffMinutes(participant.Contest.StartTime, x.CreatedOn)) + .FirstOrDefault() + }) + .OrderByDescending(x => x.Points) + .ThenBy(x => x.ExamTimeInMinutes) + .ToList(); return this.Json(participants, JsonRequestBehavior.AllowGet); } diff --git a/Open Judge System/Web/OJS.Web/Areas/Api/Controllers/SubmissionsController.cs b/Open Judge System/Web/OJS.Web/Areas/Api/Controllers/SubmissionsController.cs new file mode 100644 index 0000000000..efa088b201 --- /dev/null +++ b/Open Judge System/Web/OJS.Web/Areas/Api/Controllers/SubmissionsController.cs @@ -0,0 +1,51 @@ +namespace OJS.Web.Areas.Api.Controllers +{ + using System.Linq; + using System.Web.Mvc; + + using OJS.Common; + using OJS.Data; + using OJS.Web.Areas.Api.Models; + + public class SubmissionsController : Controller + { + public SubmissionsController(IOjsData data) + { + this.Data = data; + } + + protected IOjsData Data { get; set; } + + public ActionResult GetContestantBestSubmissions(string apiKey, string userId, int? contestId) + { + if (string.IsNullOrWhiteSpace(apiKey) || string.IsNullOrWhiteSpace(userId) || !contestId.HasValue) + { + return this.Json(new ErrorMessageViewModel("Invalid arguments!"), JsonRequestBehavior.AllowGet); + } + + var isValidApiKey = this.Data.Users + .All() + .Any(x => x.Id == apiKey && x.Roles.Any(y => y.Role.Name == GlobalConstants.AdministratorRoleName)); + if (!isValidApiKey) + { + return this.Json(new ErrorMessageViewModel("Invalid API key!"), JsonRequestBehavior.AllowGet); + } + + var submissions = this.Data.Submissions + .All() + .Where(x => x.Participant.IsOfficial && x.Participant.UserId == userId && x.Participant.ContestId == contestId.Value) + .GroupBy(x => x.Problem) + .Select(x => new + { + Problem = x.Key.Name, + Submission = x.OrderByDescending(y => y.Points) + .ThenByDescending(y => y.CreatedOn) + .Select(y => new { y.Content, y.FileExtension }) + .FirstOrDefault() + }) + .ToList(); + + return this.Json(submissions, JsonRequestBehavior.AllowGet); + } + } +} \ No newline at end of file diff --git a/Open Judge System/Web/OJS.Web/Areas/Contests/Controllers/CompeteController.cs b/Open Judge System/Web/OJS.Web/Areas/Contests/Controllers/CompeteController.cs index 294558efd8..1338607afa 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Contests/Controllers/CompeteController.cs +++ b/Open Judge System/Web/OJS.Web/Areas/Contests/Controllers/CompeteController.cs @@ -370,7 +370,7 @@ public ActionResult SubmitBinaryFile(BinarySubmissionModel participantSubmission SubmissionTypeId = participantSubmission.SubmissionTypeId, ParticipantId = participant.Id }); - + this.Data.SaveChanges(); this.TempData.Add(GlobalConstants.InfoMessage, "Solution uploaded."); diff --git a/Open Judge System/Web/OJS.Web/Areas/Contests/Controllers/SubmissionsController.cs b/Open Judge System/Web/OJS.Web/Areas/Contests/Controllers/SubmissionsController.cs index df672df218..03d99eb11b 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Contests/Controllers/SubmissionsController.cs +++ b/Open Judge System/Web/OJS.Web/Areas/Contests/Controllers/SubmissionsController.cs @@ -5,7 +5,6 @@ using System.Web; using System.Web.Mvc; - using OJS.Common.Extensions; using OJS.Data; using OJS.Web.Areas.Contests.ViewModels.Submissions; using OJS.Web.Common.Extensions; diff --git a/Open Judge System/Web/OJS.Web/Areas/Contests/ViewModels/Contests/ContestViewModel.cs b/Open Judge System/Web/OJS.Web/Areas/Contests/ViewModels/Contests/ContestViewModel.cs index 93f010bd14..55f1b41b89 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Contests/ViewModels/Contests/ContestViewModel.cs +++ b/Open Judge System/Web/OJS.Web/Areas/Contests/ViewModels/Contests/ContestViewModel.cs @@ -40,7 +40,7 @@ public static Expression> FromContest HasPracticeQuestions = contest.Questions.Any(x => x.AskPracticeParticipants), OfficialParticipants = contest.Participants.Count(x => x.IsOfficial), PracticeParticipants = contest.Participants.Count(x => !x.IsOfficial), - ProblemsCount = contest.Problems.Count(), + ProblemsCount = contest.Problems.Count(x => !x.IsDeleted), Problems = contest.Problems.AsQueryable() .Where(x => !x.IsDeleted) .OrderBy(x => x.OrderBy) @@ -66,6 +66,7 @@ public string CategoryName { return this.contestName.ToUrl(); } + set { this.contestName = value; diff --git a/Open Judge System/Web/OJS.Web/Areas/Contests/Views/List/ByCategory.cshtml b/Open Judge System/Web/OJS.Web/Areas/Contests/Views/List/ByCategory.cshtml index f06210e969..bb79da26b3 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Contests/Views/List/ByCategory.cshtml +++ b/Open Judge System/Web/OJS.Web/Areas/Contests/Views/List/ByCategory.cshtml @@ -33,7 +33,7 @@ } @if (contest.ResultsArePubliclyVisible || User.IsAdmin()) { - @Resource.Results + @Resource.Results } diff --git a/Open Judge System/Web/OJS.Web/Areas/Contests/Views/Results/Simple.cshtml b/Open Judge System/Web/OJS.Web/Areas/Contests/Views/Results/Simple.cshtml index 355518c5e9..808770239d 100644 --- a/Open Judge System/Web/OJS.Web/Areas/Contests/Views/Results/Simple.cshtml +++ b/Open Judge System/Web/OJS.Web/Areas/Contests/Views/Results/Simple.cshtml @@ -12,6 +12,11 @@ @section Styles { + }