Inheritance: IEntity
            public async Task CreatePackageWillSavePackageFileToFileStorage()
            {
                // Arrange
                var guid = Guid.NewGuid().ToString();

                var fakeUser = new User();
                var userService = new Mock<IUserService>();
                userService.Setup(x => x.FindByApiKey(It.IsAny<Guid>())).Returns(fakeUser);

                var packageRegistration = new PackageRegistration();
                packageRegistration.Owners.Add(fakeUser);

                var packageService = new Mock<IPackageService>();
                packageService.Setup(p => p.FindPackageRegistrationById(It.IsAny<string>())).Returns(packageRegistration);

                var packageFileService = new Mock<IPackageFileService>();
                packageFileService.Setup(p => p.SavePackageFileAsync(It.IsAny<Package>(), It.IsAny<Stream>())).Returns(Task.FromResult(0)).Verifiable();

                var nuGetPackage = new Mock<INupkg>();
                nuGetPackage.Setup(x => x.Metadata.Id).Returns("theId");
                nuGetPackage.Setup(x => x.Metadata.Version).Returns(new SemanticVersion("1.0.42"));

                var controller = CreateController(
                    fileService: packageFileService,
                    userService: userService,
                    packageService: packageService,
                    packageFromInputStream: nuGetPackage);

                // Act
                await controller.CreatePackagePut(guid);

                // Assert
                packageFileService.Verify();
            }
            public void WillReturnConflictIfAPackageWithTheIdAndSemanticVersionAlreadyExists()
            {
                var version = new SemanticVersion("1.0.42");
                var nuGetPackage = new Mock<IPackage>();
                nuGetPackage.Setup(x => x.Id).Returns("theId");
                nuGetPackage.Setup(x => x.Version).Returns(version);

                var user = new User();

                var packageRegistration = new PackageRegistration
                {
                    Packages = new List<Package> { new Package { Version = version.ToString() } },
                    Owners = new List<User> { user }
                };

                var packageSvc = new Mock<IPackageService>();
                packageSvc.Setup(x => x.FindPackageRegistrationById(It.IsAny<string>())).Returns(packageRegistration);
                var userSvc = new Mock<IUserService>();
                userSvc.Setup(x => x.FindByApiKey(It.IsAny<Guid>())).Returns(user);
                var controller = CreateController(userSvc: userSvc, packageSvc: packageSvc, packageFromInputStream: nuGetPackage.Object);

                // Act
                var result = controller.CreatePackagePut(Guid.NewGuid().ToString());

                // Assert
                Assert.IsType<HttpStatusCodeWithBodyResult>(result);
                var statusCodeResult = (HttpStatusCodeWithBodyResult)result;
                Assert.Equal(409, statusCodeResult.StatusCode);
                Assert.Equal(String.Format(Strings.PackageExistsAndCannotBeModified, "theId", "1.0.42"), statusCodeResult.StatusDescription);
            }
        public virtual void StartEditPackageRequest(Package p, EditPackageVersionRequest request, User editingUser)
        {
            PackageEdit edit = new PackageEdit
            {
                // Description
                User = editingUser,
                Authors = request.Authors,
                Copyright = request.Copyright,
                Description = request.Description,
                IconUrl = request.IconUrl,
                LicenseUrl = p.LicenseUrl, // Our current policy is not to allow editing the license URL, so just clone it from its previous value.
                ProjectUrl = request.ProjectUrl,
                ReleaseNotes = request.ReleaseNotes,
                RequiresLicenseAcceptance = request.RequiresLicenseAcceptance,
                Summary = request.Summary,
                Tags = request.Tags,
                Title = request.VersionTitle,

                // Other
                Package = p,
                Timestamp = DateTime.UtcNow,
                TriedCount = 0,
            };

            EntitiesContext.Set<PackageEdit>().Add(edit);
            // Note: EditPackageRequests are completed asynchronously by the worker role.
        }
Esempio n. 4
0
            public async Task CreatePackageWillSavePackageFileToFileStorage()
            {
                // Arrange
                var user = new User() { EmailAddress = "*****@*****.**" };
                var packageRegistration = new PackageRegistration();
                packageRegistration.Id = "theId";
                packageRegistration.Owners.Add(user);
                var package = new Package();
                package.PackageRegistration = packageRegistration;
                package.Version = "1.0.42";
                packageRegistration.Packages.Add(package);

                var controller = new TestableApiController();
                controller.SetCurrentUser(user);
                controller.MockPackageFileService.Setup(p => p.SavePackageFileAsync(It.IsAny<Package>(), It.IsAny<Stream>()))
                    .Returns(Task.CompletedTask).Verifiable();
                controller.MockPackageService.Setup(p => p.FindPackageRegistrationById(It.IsAny<string>()))
                    .Returns(packageRegistration);
                controller.MockPackageService.Setup(p => p.CreatePackageAsync(It.IsAny<PackageArchiveReader>(), It.IsAny<PackageStreamMetadata>(), It.IsAny<User>(), false))
                    .Returns(Task.FromResult(package));

                var nuGetPackage = TestPackage.CreateTestPackageStream("theId", "1.0.42");
                controller.SetupPackageFromInputStream(nuGetPackage);

                // Act
                await controller.CreatePackagePut();

                // Assert
                controller.MockPackageFileService.Verify();
            }
        public bool ConfirmPackageOwner(PackageRegistration package, User pendingOwner, string token)
        {
            if (package == null)
            {
                throw new ArgumentNullException("package");
            }

            if (pendingOwner == null)
            {
                throw new ArgumentNullException("pendingOwner");
            }

            if (String.IsNullOrEmpty(token))
            {
                throw new ArgumentNullException("token");
            }

            if (package.IsOwner(pendingOwner))
            {
                return true;
            }

            var request = FindExistingPackageOwnerRequest(package, pendingOwner);
            if (request != null && request.ConfirmationCode == token)
            {
                AddPackageOwner(package, pendingOwner);
                return true;
            }

            return false;
        }
Esempio n. 6
0
        public Package CreatePackage(IPackage nugetPackage, User currentUser)
        {
            ValidateNuGetPackage(nugetPackage);

            var packageRegistration = CreateOrGetPackageRegistration(currentUser, nugetPackage);

            var package = CreatePackageFromNuGetPackage(packageRegistration, nugetPackage);
            packageRegistration.Packages.Add(package);

            using (var tx = new TransactionScope())
            {
                using (var stream = nugetPackage.GetStream())
                {
                    UpdateIsLatest(packageRegistration);
                    packageRegistrationRepo.CommitChanges();
                    packageFileSvc.SavePackageFile(package, stream);
                    tx.Complete();
                }
            }

            if (package.Status != PackageStatusType.Approved && package.Status != PackageStatusType.Exempted) NotifyForModeration(package, comments: string.Empty);

            NotifyIndexingService();

            return package;
        }
        public IEnumerable<UserSiteProfile> GetUserProfiles(User user)
        {
            return profileRepo.GetAll().Where(x => x.Username == user.Username).ToList();

            //return (from p in profileRepo.GetAll()
            //        where p.Username == user.Username
            //        select p).ToList();
        }
            public async Task WithTokenThatDoesNotMatchUserReturnsFalse()
            {
                var user = new User { Username = "******", EmailConfirmationToken = "token" };
                var service = new TestableUserService();

                var confirmed = await service.ConfirmEmailAddress(user, "not-token");

                Assert.False(confirmed);
            }
Esempio n. 9
0
        public void ChangeEmailSubscription(User user, bool emailAllowed)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            user.EmailAllowed = emailAllowed;
            UserRepository.CommitChanges();
        }
Esempio n. 10
0
        public void ChangeEmailAddress(User user, string newEmailAddress)
        {
            var existingUsers = FindAllByEmailAddress(newEmailAddress);
            if (existingUsers.AnySafe(u => u.Key != user.Key))
            {
                throw new EntityException(Strings.EmailAddressBeingUsed, newEmailAddress);
            }

            user.UpdateEmailAddress(newEmailAddress, Crypto.GenerateToken);
            UserRepository.CommitChanges();
        }
Esempio n. 11
0
        public async Task ChangeEmailSubscriptionAsync(User user, bool emailAllowed, bool notifyPackagePushed)
        {
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }

            user.EmailAllowed = emailAllowed;
            user.NotifyPackagePushed = notifyPackagePushed;
            await UserRepository.CommitChangesAsync();
        }
Esempio n. 12
0
        public void IsInRoleReturnsCorrectValue(string expectedRole, bool isInRole)
        {
            // Arrange
            var user = new User("testuser");
            user.Roles.Add(new Role { Key = 1, Name = "Admins" });

            // Act
            var result = user.IsInRole(expectedRole);

            // Assert
            Assert.True(result == isInRole);
        }
Esempio n. 13
0
        public void AddPackageOwner(PackageRegistration package, User user)
        {
            package.Owners.Add(user);
            packageRepo.CommitChanges();

            var request = FindExistingPackageOwnerRequest(package, user);
            if (request != null)
            {
                packageOwnerRequestRepository.DeleteOnCommit(request);
                packageOwnerRequestRepository.CommitChanges();
            }
        }
            public async Task ThrowsForDuplicateConfirmedEmailAddresses()
            {
                var user = new User { Username = "******", Key = 1, EmailAddress = "*****@*****.**", UnconfirmedEmailAddress = "*****@*****.**", EmailConfirmationToken = "token" };
                var conflictingUser = new User { Username = "******", Key = 2, EmailAddress = "*****@*****.**" };
                var service = new TestableUserServiceWithDBFaking
                {
                    Users = new[] { user, conflictingUser }
                };

                var ex = await AssertEx.Throws<EntityException>(() => service.ConfirmEmailAddress(user, "token"));
                Assert.Equal(String.Format(Strings.EmailAddressBeingUsed, "*****@*****.**"), ex.Message);
            }
        public async Task SoftDeletePackagesAsync(IEnumerable<Package> packages, User deletedBy, string reason, string signature)
        {
            EntitiesConfiguration.SuspendExecutionStrategy = true;
            using (var transaction = _entitiesContext.GetDatabase().BeginTransaction())
            {
                // Increase command timeout
                _entitiesContext.SetCommandTimeout(seconds: 300);

                // Keep package registrations
                var packageRegistrations = packages
                    .GroupBy(p => p.PackageRegistration)
                    .Select(g => g.First().PackageRegistration)
                    .ToList();

                // Backup the package binaries and remove from main storage
                // We're doing this early in the process as we need the metadata to still exist in the DB.
                await BackupPackageBinaries(packages);

                // Store the soft delete in the database
                var packageDelete = new PackageDelete
                {
                    DeletedOn = DateTime.UtcNow,
                    DeletedBy = deletedBy,
                    Reason = reason,
                    Signature = signature
                };

                foreach (var package in packages)
                {
                    package.Listed = false;
                    package.Deleted = true;
                    packageDelete.Packages.Add(package);

                    await _auditingService.SaveAuditRecord(CreateAuditRecord(package, package.PackageRegistration, AuditedPackageAction.SoftDelete, reason));
                }

                _packageDeletesRepository.InsertOnCommit(packageDelete);

                // Update latest versions
                await UpdateIsLatestAsync(packageRegistrations);

                // Commit changes
                await _packageRepository.CommitChangesAsync();
                await _packageDeletesRepository.CommitChangesAsync();
                transaction.Commit();
            }
            EntitiesConfiguration.SuspendExecutionStrategy = false;


            // Force refresh the index
            UpdateSearchIndex();
        }
Esempio n. 16
0
        public static bool VerifyPasswordHash(User user, string password)
        {
            bool canAuthenticate = CryptographyService.ValidateSaltedHash(
                user.HashedPassword,
                password,
                user.PasswordHashAlgorithm);

            bool sanity = CryptographyService.ValidateSaltedHash(
                user.HashedPassword,
                "not_the_password",
                user.PasswordHashAlgorithm);

            return canAuthenticate && !sanity;
        }
        public void SaveProfiles(User user, EditProfileViewModel profile)
        {
            var siteProfiles = GetUserProfiles(user).AsQueryable();

            CompareAndPrepareProfile(SiteProfileConstants.Blog, profile.BlogUrl, user.Username, string.Empty, siteProfiles, prefix: string.Empty);
            CompareAndPrepareProfile(SiteProfileConstants.Codeplex, profile.CodeplexUserName, user.Username, SiteProfileConstants.Images.codeplex, siteProfiles, prefix: SiteProfileConstants.CodeplexProfilePrefix);
            CompareAndPrepareProfile(SiteProfileConstants.Github, profile.GithubUserName, user.Username, SiteProfileConstants.Images.github, siteProfiles, prefix: SiteProfileConstants.GithubProfilePrefix);
            CompareAndPrepareProfile(SiteProfileConstants.Homepage, profile.HomepageUrl, user.Username, string.Empty, siteProfiles, prefix: string.Empty);
            CompareAndPrepareProfile(SiteProfileConstants.StackExchange, profile.StackExchangeUrl, user.Username, SiteProfileConstants.Images.stackexchange, siteProfiles, prefix: string.Empty);
            CompareAndPrepareProfile(SiteProfileConstants.Twitter, profile.TwitterUserName, user.Username, SiteProfileConstants.Images.twitter, siteProfiles, prefix: SiteProfileConstants.TwitterProfilePrefix);
            CompareAndPrepareProfile(SiteProfileConstants.PackagesRepository, profile.PackagesRepository, user.Username, string.Empty, siteProfiles, prefix: string.Empty);
            CompareAndPrepareProfile(SiteProfileConstants.PackagesRepositoryAuto, profile.PackagesRepositoryAuto, user.Username, string.Empty, siteProfiles, prefix: string.Empty);

            profileRepo.CommitChanges();
        }
Esempio n. 18
0
            public void WillCreateAPackageWithTheUserMatchingTheApiKey()
            {
                var nuGetPackage = new Mock<IPackage>();
                nuGetPackage.Setup(x => x.Id).Returns("theId");
                nuGetPackage.Setup(x => x.Version).Returns(new SemanticVersion("1.0.42"));
                var packageSvc = new Mock<IPackageService>();
                var userSvc = new Mock<IUserService>();
                var matchingUser = new User();
                userSvc.Setup(x => x.FindByApiKey(It.IsAny<Guid>())).Returns(matchingUser);
                var controller = CreateController(userSvc: userSvc, packageSvc: packageSvc, packageFromInputStream: nuGetPackage.Object);

                controller.CreatePackagePut(Guid.NewGuid());

                packageSvc.Verify(x => x.CreatePackage(It.IsAny<IPackage>(), matchingUser));
            }
Esempio n. 19
0
            public void ReturnsTrueWhenSuccessful()
            {
                var user = new User { Username = "******", HashedPassword = "******", PasswordHashAlgorithm = "PBKDF2" };
                var userRepository = new Mock<IEntityRepository<User>>();
                userRepository.Setup(r => r.GetAll()).Returns(new[] { user }.AsQueryable());
                var cryptoService = new Mock<ICryptographyService>(MockBehavior.Strict);
                cryptoService.Setup(s => s.ValidateSaltedHash("old hash", "oldpwd", Constants.PBKDF2HashAlgorithmId)).Returns(true);
                cryptoService.Setup(s => s.GenerateSaltedHash("newpwd", Constants.PBKDF2HashAlgorithmId)).Returns("hash and bacon");
                var service = CreateUsersService(userRepo: userRepository, cryptoService: cryptoService);

                var changed = service.ChangePassword("user", "oldpwd", "newpwd");

                Assert.True(changed);
                Assert.Equal("hash and bacon", user.HashedPassword);
            }
Esempio n. 20
0
        public virtual User Create(
            string username,
            string password,
            string emailAddress)
        {
            // TODO: validate input
            // TODO: consider encrypting email address with a public key, and having the background process that send messages have the private key to decrypt

            var existingUser = FindByUsername(username);
            if (existingUser != null)
            {
                throw new EntityException(Strings.UsernameNotAvailable, username);
            }

            var existingUsers = FindAllByEmailAddress(emailAddress);
            if (existingUsers.AnySafe())
            {
                throw new EntityException(Strings.EmailAddressBeingUsed, emailAddress);
            }

            var hashedPassword = Crypto.GenerateSaltedHash(password, Constants.PBKDF2HashAlgorithmId);

            var apiKey = Guid.NewGuid();
            var newUser = new User(username)
            {
                ApiKey = apiKey,
                EmailAllowed = true,
                UnconfirmedEmailAddress = emailAddress,
                EmailConfirmationToken = Crypto.GenerateToken(),
                HashedPassword = hashedPassword,
                PasswordHashAlgorithm = Constants.PBKDF2HashAlgorithmId,
                CreatedUtc = DateTime.UtcNow
            };

            // Add a credential for the password and the API Key
            newUser.Credentials.Add(CredentialBuilder.CreateV1ApiKey(apiKey));
            newUser.Credentials.Add(new Credential(CredentialTypes.Password.Pbkdf2, newUser.HashedPassword));

            if (!Config.ConfirmEmailAddresses)
            {
                newUser.ConfirmEmailAddress();
            }

            UserRepository.InsertOnCommit(newUser);
            UserRepository.CommitChanges();

            return newUser;
        }
            public void WillGetCuratedFeedsManagedByTheCurrentUser()
            {
                var controller = GetController<UsersController>();
                var user = new User { Username = "******", Key = 42 };
                controller.SetUser(user);
                GetMock<IUserService>()
                          .Setup(s => s.FindByUsername(It.IsAny<string>()))
                          .Returns(user);
                
                // act
                controller.Account();

                // verify
                GetMock<ICuratedFeedService>()
                    .Verify(query => query.GetFeedsForManager(42));
            }
            public void WillReturnTheAccountViewModelWithTheUserApiKey()
            {
                var controller = GetController<UsersController>();
                var stubApiKey = Guid.NewGuid();
                var user = new User { Username = "******", Key = 42, ApiKey = stubApiKey };
                GetMock<IUserService>()
                    .Setup(s => s.FindByUsername(It.IsAny<string>()))
                    .Returns(user);
                controller.SetUser(user);

                // act
                var model = ((ViewResult)controller.Account()).Model as AccountViewModel;

                // verify
                Assert.Equal(stubApiKey.ToString(), model.ApiKey);
            }
            public void WillGetTheCurrentUserUsingTheRequestIdentityName()
            {
                var controller = GetController<UsersController>();
                var user = new User { Username = "******" };
                controller.SetUser(user);
                GetMock<IUserService>()
                          .Setup(s => s.FindByUsername(It.IsAny<string>()))
                          .Returns(user);

                //act
                controller.Account();

                // verify
                GetMock<IUserService>()
                          .Verify(stub => stub.FindByUsername("theUsername"));
            }
            public void ReturnsConfirmedWhenTokenMatchesUser()
            {
                var user = new User
                {
                    UnconfirmedEmailAddress = "*****@*****.**",
                    EmailConfirmationToken = "the-token"
                };
                var userService = new Mock<IUserService>();
                userService.Setup(u => u.FindByUsername("username")).Returns(user);
                userService.Setup(u => u.ConfirmEmailAddress(user, "the-token")).Returns(true);
                var controller = CreateController(userSvc: userService);

                var model = (controller.Confirm("username", "the-token") as ViewResult).Model as EmailConfirmationModel;

                Assert.True(model.SuccessfulConfirmation);
            }
Esempio n. 25
0
            public void ReturnsTrueWhenSuccessful()
            {
                var user = new User { Username = "******", HashedPassword = "******", PasswordHashAlgorithm = "PBKDF2" };
                var service = new TestableUserService();
                service.MockUserRepository
                       .Setup(r => r.GetAll()).Returns(new[] { user }.AsQueryable());
                service.MockCrypto
                       .Setup(s => s.ValidateSaltedHash("old hash", "oldpwd", Constants.PBKDF2HashAlgorithmId)).Returns(true);
                service.MockCrypto
                       .Setup(s => s.GenerateSaltedHash("newpwd", Constants.PBKDF2HashAlgorithmId)).Returns("hash and bacon");

                var changed = service.ChangePassword("user", "oldpwd", "newpwd");

                Assert.True(changed);
                Assert.Equal("hash and bacon", user.HashedPassword);
            }
Esempio n. 26
0
            public void WillSendEmailToGalleryOwner()
            {
                var from = new MailAddress("*****@*****.**", "too");
                var owner = new User
                {
                    Username = "******",
                    EmailAddress = "*****@*****.**",
                };
                var package = new Package
                {
                    PackageRegistration = new PackageRegistration
                    {
                        Id = "smangit", 
                        Owners = new Collection<User> { owner }
                    },
                    Version = "1.42.0.1"
                };
                var mailSender = new Mock<IMailSender>();
                var config = new Mock<IConfiguration>();
                config.Setup(x => x.GalleryOwnerName).Returns("NuGet Gallery");
                config.Setup(x => x.GalleryOwnerEmail).Returns("*****@*****.**");
                var messageService = new MessageService(mailSender.Object, config.Object);
                MailMessage message = null;
                mailSender.Setup(m => m.Send(It.IsAny<MailMessage>())).Callback<MailMessage>(m => { message = m; });

                messageService.ReportMyPackage(
                    new ReportPackageRequest
                    {
                        FromAddress = from,
                        Message = "Abuse!",
                        Package = package,
                        Reason = "Reason!",
                        RequestingUser = owner,
                        Url = TestUtility.MockUrlHelper(),
                    });

                Assert.Equal("*****@*****.**", message.To[0].Address);
                Assert.Equal("*****@*****.**", message.From.Address);
                Assert.Equal("*****@*****.**", message.ReplyToList.Single().Address);
                Assert.Equal("[NuGet Gallery] Owner Support Request for 'smangit' version 1.42.0.1 (Reason: Reason!)", message.Subject);
                Assert.Contains("Reason!", message.Body);
                Assert.Contains("Abuse!", message.Body);
                Assert.Contains("too ([email protected])", message.Body);
                Assert.Contains("smangit", message.Body);
                Assert.Contains("1.42.0.1", message.Body);
            }
Esempio n. 27
0
        public Package CreatePackage(INupkg nugetPackage, User user, bool commitChanges = true)
        {
            ValidateNuGetPackageMetadata(nugetPackage.Metadata);

            var packageRegistration = CreateOrGetPackageRegistration(user, nugetPackage.Metadata);

            var package = CreatePackageFromNuGetPackage(packageRegistration, nugetPackage, user);
            packageRegistration.Packages.Add(package);
            UpdateIsLatest(packageRegistration, commitChanges);

            if (commitChanges)
            {
                _packageRegistrationRepository.CommitChanges();
                NotifyIndexingService();
            }

            return package;
        }
            public void WillReturnTheAccountViewModelWithTheCuratedFeeds()
            {
                var user = new User { Key = 42, Username = "******" };
                var controller = GetController<UsersController>();
                GetMock<IUserService>()
                    .Setup(s => s.FindByUsername(It.IsAny<string>()))
                    .Returns(user);
                GetMock<ICuratedFeedService>()
                    .Setup(stub => stub.GetFeedsForManager(It.IsAny<int>()))
                    .Returns(new[] { new CuratedFeed { Name = "theCuratedFeed" } });
                controller.SetUser(user);

                // act
                var model = ((ViewResult)controller.Account()).Model as AccountViewModel;

                // verify
                Assert.Equal("theCuratedFeed", model.CuratedFeeds.First());
            }
Esempio n. 29
0
            public void WillMakeTheCurrentUserTheOwnerWhenCreatingANewPackageRegistration()
            {
                var packageRegistrationRepo = new Mock<IEntityRepository<PackageRegistration>>();
                var service = CreateService(
                    packageRegistrationRepo: packageRegistrationRepo,
                    setup: mockPackageSvc =>
                    {
                        mockPackageSvc.Setup(x => x.FindPackageRegistrationById(It.IsAny<string>())).Returns((PackageRegistration)null);
                    });
                var nugetPackage = CreateNuGetPackage();
                var currentUser = new User();

                var package = service.CreatePackage(
                    nugetPackage.Object,
                    currentUser);

                packageRegistrationRepo.Verify(x => x.InsertOnCommit(It.Is<PackageRegistration>(pr => pr.Owners.Contains(currentUser))));
            }
Esempio n. 30
0
            public void WillCreateANewPackageRegistrationUsingTheNugetPackIdWhenOneDoesNotAlreadyExist()
            {
                var packageRegistrationRepo = new Mock<IEntityRepository<PackageRegistration>>();
                var service = CreateService(
                    packageRegistrationRepo: packageRegistrationRepo,
                    setup: mockPackageSvc =>
                    {
                        mockPackageSvc.Setup(x => x.FindPackageRegistrationById(It.IsAny<string>())).Returns((PackageRegistration)null);
                    });
                var nugetPackage = CreateNuGetPackage();
                var currentUser = new User();

                var package = service.CreatePackage(
                    nugetPackage.Object,
                    currentUser);

                packageRegistrationRepo.Verify(x => x.InsertOnCommit(It.Is<PackageRegistration>(pr => pr.Id == "theId")));
                packageRegistrationRepo.Verify(x => x.CommitChanges());
            }
        public virtual ActionResult DisplayPackage(string id, string version, FormCollection form)
        {
            if (!ModelState.IsValid) return DisplayPackage(id, version);
            var currentUser = userSvc.FindByUsername(GetIdentity().Name);

            var package = packageSvc.FindPackageByIdAndVersion(id, version, allowPrerelease: true, useCache: false);

            if (package == null) return PackageNotFound(id, version);
            var scanResults = packageSvc.GetPackageScanResults(id, version,useCache:false);
            var model = new DisplayPackageViewModel(package, scanResults);

            var packageRegistration = package.PackageRegistration;
            var isMaintainer = packageRegistration.Owners.AnySafe(x => x.Key == currentUser.Key);
            var isModerationRole = User.IsInAnyModerationRole() && !isMaintainer;
            var isModerator = User.IsModerator() && !isMaintainer;

            if (packageRegistration != null && !isMaintainer && !isModerationRole)
            {
                ModelState.AddModelError(String.Empty, String.Format(CultureInfo.CurrentCulture, Strings.ApiKeyNotAuthorized, "maintain"));
                return View("~/Views/Packages/DisplayPackage.cshtml", model);
            }

            if (!ModelState.IsValid) return View("~/Views/Packages/DisplayPackage.cshtml", model);

            var status = PackageStatusType.Unknown;
            if (isMaintainer)
            {
                status = package.Status;
            }
            else
            {
                try
                {
                    status = (PackageStatusType)Enum.Parse(typeof(PackageStatusType), form["Status"].clean_html());
                }
                catch (Exception ex)
                {
                    // Log but swallow the exception
                    ErrorSignal.FromCurrentContext().Raise(ex);
                }
            }

            // maintainers and reviewers cannot change the current status
            if (User.IsReviewer() || isMaintainer) status = package.Status;

            if (package.Status != PackageStatusType.Unknown && status == PackageStatusType.Unknown)
            {
                ModelState.AddModelError(String.Empty, "A package cannot be moved into unknown status.");
                return View("~/Views/Packages/DisplayPackage.cshtml", model);
            }
            if (package.Status == PackageStatusType.Unknown && status == PackageStatusType.Submitted)
            {
                ModelState.AddModelError(String.Empty, "A package cannot be moved from unknown to submitted status.");
                return View("~/Views/Packages/DisplayPackage.cshtml", model);
            }

            if (User.IsReviewer() && status != PackageStatusType.Submitted)
            {
                ModelState.AddModelError(String.Empty, "A reviewer can only comment/submit in submitted status.");
                return View("~/Views/Packages/DisplayPackage.cshtml", model);
            }

            var reviewedPlusOneHour = package.ReviewedDate.GetValueOrDefault().AddHours(1);
            if (!User.IsAdmin() 
                && package.Status != status 
                && reviewedPlusOneHour < DateTime.UtcNow 
                && (package.Status == PackageStatusType.Approved 
                                      || package.Status == PackageStatusType.Exempted 
                                      || package.Status == PackageStatusType.Rejected
                   )
                )
            {
                ModelState.AddModelError(String.Empty, "Only an admin can move a package from approved/exempt/rejected after one hour of status change. Please reach out on Gitter or use contact site admins link in the left side bar.");
                return View("~/Views/Packages/DisplayPackage.cshtml", model);
            }

            var newComments = form["NewReviewComments"].clean_html();
            bool sendMaintainerEmail = form["SendEmail"].clean_html() == "true";
            bool trustedPackage = form["IsTrusted"].clean_html() == "true,false";
            bool maintainerReject = form["MaintainerReject"].clean_html() == "true";
            bool changeSubmittedStatus = form["ChangeSubmittedStatus"].clean_html() == "true";

            //if (comments != package.ReviewComments)
            //{
            //    ModelState.AddModelError(String.Empty, "New comments have been added, please reload.");
            //    return View("~/Views/Packages/DisplayPackage.cshtml", model);
            //}

            if (maintainerReject && string.IsNullOrWhiteSpace(newComments))
            {
                ModelState.AddModelError(String.Empty, "In order to reject a package version, you must provide comments indicating why it is being rejected.");
                return View("~/Views/Packages/DisplayPackage.cshtml", model);
            }

            if (isMaintainer && string.IsNullOrWhiteSpace(newComments))
            {
                ModelState.AddModelError(String.Empty, "You need to provide comments.");
                return View("~/Views/Packages/DisplayPackage.cshtml", model);
            }

            if (isMaintainer && maintainerReject)
            {
                status = PackageStatusType.Rejected;
            }

            bool exemptVerfication = form["IsExemptedFromVerification"].clean_html() == "true,false";
            var exemptVerficationReason = form["ExemptedFromVerificationReason"].clean_html();
            if (exemptVerfication && string.IsNullOrWhiteSpace(exemptVerficationReason))
            {
                ModelState.AddModelError(String.Empty, "In order to exempt a package from automated testing, a reason should be specified.");
                return View("~/Views/Packages/DisplayPackage.cshtml", model);
            }

            if (isModerationRole)
            {
                packageSvc.ExemptPackageFromTesting(package, exemptVerfication, exemptVerficationReason, currentUser);
            }

            bool rerunTests = form["RerunTests"].clean_html() == "true";
            if (rerunTests)
            {
                packageSvc.ResetPackageTestStatus(package);
                if (!string.IsNullOrWhiteSpace(newComments)) newComments += "{0}".format_with(Environment.NewLine);
                newComments += "Auto Verification Change - Verification tests have been set to rerun.";
            }

            bool rerunVirusScanner = form["RerunVirusScanner"].clean_html() == "true";
            if (rerunVirusScanner)
            {
                package.PackageScanStatus = PackageScanStatusType.Unknown;
                packageSvc.SaveMinorPackageChanges(package);
                if (!string.IsNullOrWhiteSpace(newComments)) newComments += "{0}".format_with(Environment.NewLine);
                newComments += "Virus Scanner has ben set to rerun";
            }
            
            // could be null if no moderation has happened yet
            var moderator = isModerationRole ? currentUser : package.ReviewedBy;

            packageSvc.ChangePackageStatus(package, status, package.ReviewComments, newComments, currentUser, 
                moderator, sendMaintainerEmail, 
                isModerationRole ? 
                    changeSubmittedStatus ? 
                        PackageSubmittedStatusType.Waiting 
                        : package.SubmittedStatus 
                    : PackageSubmittedStatusType.Responded, 
                    assignReviewer: true
            );

            if (isModerator)
            {
                packageSvc.ChangeTrustedStatus(package, trustedPackage, moderator);
            }

            //grab updated package
            package = packageSvc.FindPackageByIdAndVersion(id, version, allowPrerelease: true, useCache: false);
            scanResults = packageSvc.GetPackageScanResults(id, version, useCache:false);
            model = new DisplayPackageViewModel(package, scanResults);

            TempData["Message"] = "Changes to package status have been saved.";

            return View("~/Views/Packages/DisplayPackage.cshtml", model);
        }