Example #1
0
 /// <summary>
 /// Removes the specified login from the user
 /// </summary>
 /// <param name="userId">User ID</param>
 /// <param name="providerId">ProviderId</param>
 public async Task RemoveLogin(string userId, string providerId)
 {
     using (var ctx = DataAccessFactory.CreateContext <ISecurityDataOperations>())
     {
         await ctx.RemoveLogin(userId, providerId);
     }
 }
        public void ForeignKeyExceptionIsRecognized1()
        {
            // --- Arrange
            var parent = new ParentRecord
            {
                Name = "Parent",
            };
            var child = new ChildRecord
            {
                Name     = "Child1",
                Value    = 1,
                ParentId = -1
            };

            // --- Act
            ForeignKeyViolationException exCaught = null;

            try
            {
                using (var ctx = DataAccessFactory.CreateContext <ITestDataOperations>())
                {
                    ctx.InsertParent(parent, false);
                    ctx.InsertChild(child);
                }
            }
            catch (ForeignKeyViolationException ex)
            {
                exCaught = ex;
            }

            // --- Assert
            // ReSharper disable once PossibleNullReferenceException
            exCaught.KeyName.ShouldEqual("FK_Child_ToParent");
        }
        public void PrimaryKeyExceptionIsRecognized()
        {
            // --- Arrange
            var parent = new ParentRecord
            {
                Name = "Parent"
            };

            // --- Act
            PrimaryKeyViolationException exCaught = null;

            try
            {
                using (var ctx = DataAccessFactory.CreateContext <ITestDataOperations>())
                {
                    ctx.InsertParent(parent, false);
                    ctx.InsertParent(parent, true);
                }
            }
            catch (PrimaryKeyViolationException ex)
            {
                exCaught = ex;
            }

            // --- Assert
            // ReSharper disable once PossibleNullReferenceException
            exCaught.TableName.ShouldEqual("dbo.Parent");
        }
        /// <summary>
        /// Stores the specified configuration value
        /// </summary>
        /// <param name="category">Configuration item category</param>
        /// <param name="key">Configuration key</param>
        /// <param name="value">Configuration value</param>
        public void SetConfigurationValue(string category, string key, string value)
        {
            using (var ctx = DataAccessFactory.CreateContext <IConfigurationDataOperations>())
            {
                var currentVersion = ctx.GetCurrentConfigurationVersion();
                if (currentVersion == null)
                {
                    throw new CurrentVersionNotFoundException();
                }
                var versionId = currentVersion.CurrentVersion;

                if (value == null)
                {
                    ctx.DeleteConfigurationValue(versionId, category, key);
                    return;
                }

                var valueInDb = ctx.GetConfigurationValueByKey(versionId, category, key);
                if (valueInDb == null)
                {
                    ctx.InsertConfigurationValue(new ConfigurationValueRecord
                    {
                        VersionId = versionId,
                        Category  = category,
                        ConfigKey = key,
                        Value     = value
                    });
                }
                else if (value != valueInDb.Value)
                {
                    valueInDb.Value = value;
                    ctx.UpdateConfigurationValue(valueInDb);
                }
            }
        }
Example #5
0
        public async Task BeginTransactionWorksAsExpected()
        {
            // --- Arrange
            var data = new DataRecord
            {
                Name = "Data"
            };

            // --- Act
            using (var dc = DataAccessFactory.CreateContext <ITestDataOperations>())
            {
                await dc.BeginTransactionAsync();

                await dc.InsertDataAsync(data);

                await dc.CompleteAsync();
            }

            // --- Assert
            DataRecord back;

            using (var dc = DataAccessFactory.CreateReadOnlyContext <ITestDataOperations>())
            {
                back = await dc.GetDataAsync(data.Id);
            }

            back.ShouldNotBeNull();
        }
        public void NullValueNotAllowedExceptionIsRecognized2()
        {
            // --- Arrange
            var child = new ChildRecord
            {
                Name  = "Child",
                Value = 2
            };

            using (var ctx = DataAccessFactory.CreateContext <ITestDataOperations>())
            {
                ctx.InsertChild(child);
            }

            // --- Act
            NullValueNotAllowedException exCaught = null;

            try
            {
                using (var ctx = DataAccessFactory.CreateContext <ITestDataOperations>())
                {
                    child.Value = null;
                    ctx.UpdateChild(child);
                }
            }
            catch (NullValueNotAllowedException ex)
            {
                exCaught = ex;
            }

            // --- Assert
            // ReSharper disable once PossibleNullReferenceException
            exCaught.TableName.ShouldEqual("Seemplest.Test.dbo.Child");
            exCaught.ColumnName.ShouldEqual("Value");
        }
        /// <summary>
        /// Modifies a dive log entry
        /// </summary>
        /// <param name="dive">The dive log entry to save</param>
        public async Task ModifyDiveLogEntryAsync(DiveLogEntryDto dive)
        {
            ValidateDiveLogArgument(dive);
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <IDiveLogDataAccessOperations>())
            {
                var diveRecord = await ctx.GetDiveLogByIdAsync(dive.Id);

                if (diveRecord == null)
                {
                    throw new DiveNotFoundException(dive.Id);
                }

                if (diveRecord.UserId != ServicedUserId)
                {
                    throw new NoPermissionToDiveLogException(diveRecord.Id, ServicedUserId, diveRecord.UserId);
                }

                diveRecord.Date       = dive.Date;
                diveRecord.DiveSite   = dive.DiveSite;
                diveRecord.Location   = dive.Location;
                diveRecord.MaxDepth   = dive.MaxDepth;
                diveRecord.BottomTime = dive.BottomTime;
                diveRecord.Comment    = dive.Comment;
                await ctx.UpdateDiveLogEntryAsync(diveRecord);
            }
        }
        public void CheckConstraintViolationExceptionIsRecognized2()
        {
            // --- Arrange
            var child = new ChildRecord
            {
                Name  = "Child",
                Value = 4
            };

            using (var ctx = DataAccessFactory.CreateContext <ITestDataOperations>())
            {
                ctx.InsertChild(child);
            }

            // --- Act
            CheckConstraintViolationException exCaught = null;

            try
            {
                using (var ctx = DataAccessFactory.CreateContext <ITestDataOperations>())
                {
                    child.Value = 14;
                    ctx.UpdateChild(child);
                }
            }
            catch (CheckConstraintViolationException ex)
            {
                exCaught = ex;
            }

            // --- Assert
            // ReSharper disable once PossibleNullReferenceException
            exCaught.TableName.ShouldEqual("dbo.Child");
            exCaught.CheckName.ShouldEqual("CK_Child_Value");
        }
        public void UniqueKeyExceptionIsRecognized1()
        {
            // --- Arrange
            var child1 = new ChildRecord
            {
                Name  = "Child1",
                Value = 1
            };
            var child2 = new ChildRecord
            {
                Name  = "Child1",
                Value = 2
            };

            // --- Act
            UniqueKeyViolationException exCaught = null;

            try
            {
                using (var ctx = DataAccessFactory.CreateContext <ITestDataOperations>())
                {
                    ctx.InsertChild(child1);
                    ctx.InsertChild(child2);
                }
            }
            catch (UniqueKeyViolationException ex)
            {
                exCaught = ex;
            }

            // --- Assert
            // ReSharper disable once PossibleNullReferenceException
            exCaught.TableName.ShouldEqual("dbo.Child");
            exCaught.KeyName.ShouldEqual("AK_Child_Name");
        }
        public void AbortTransactionWorksAsExpected()
        {
            // --- Arrange
            var data = new DataRecord
            {
                Name = "Data"
            };

            // --- Act
            using (var dc = DataAccessFactory.CreateContext <ITestDataOperations>())
            {
                dc.BeginTransaction();
                dc.InsertData(data);
                dc.AbortTransaction();
            }

            // --- Assert
            DataRecord back;

            using (var dc = DataAccessFactory.CreateReadOnlyContext <ITestDataOperations>())
            {
                back = dc.GetData(data.Id);
            }

            back.ShouldBeNull();
        }
Example #11
0
 /// <summary>
 /// Updates the specified user in the user database
 /// </summary>
 /// <param name="user">User information</param>
 public async Task UpdateUserAsync(UserInfoDto user)
 {
     using (var ctx = DataAccessFactory.CreateContext <ISecurityDataOperations>())
     {
         await ctx.UpdateUserAsync(MapUser(user));
     }
 }
        /// <summary>
        /// Removes the specified user account from the database
        /// </summary>
        /// <param name="userId">User ID</param>
        /// <param name="provider">Account provider</param>
        public async Task RemoveUserAccountAsync(Guid userId, string provider)
        {
            Verify.NotNullOrEmpty(provider, "provider");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <ISubscriptionDataOperations>())
            {
                await ctx.DeleteUserAccountAsync(userId, provider);
            }
        }
Example #13
0
 /// <summary>
 /// Inserts a new user account into the database
 /// </summary>
 /// <param name="userAccount">User account information</param>
 public async Task InsertUserAccount(UserAccountDto userAccount)
 {
     using (var ctx = DataAccessFactory.CreateContext <ISecurityDataOperations>())
     {
         await ctx.InsertUserAccountAsync(new UserAccountRecord
         {
             UserId       = userAccount.UserId,
             Provider     = userAccount.Provider,
             ProviderData = userAccount.ProviderData
         });
     }
 }
        /// <summary>
        /// Assigns the specified user to the given subscription
        /// </summary>
        /// <param name="userId">User ID</param>
        /// <param name="subscriptionId">Subscription ID</param>
        public async Task AssignUserToSubscription(Guid userId, int subscriptionId)
        {
            using (var ctx = DataAccessFactory.CreateContext <ISubscriptionDataOperations>())
            {
                var user = await ctx.GetUserByIdAsync(userId);

                if (user == null)
                {
                    throw new UnknownUserIdException(userId.ToString());
                }
                user.SubscriptionId = subscriptionId;
                await ctx.UpdateUserAsync(user);
            }
        }
        /// <summary>
        /// Processes the specified email
        /// </summary>
        /// <param name="emailToSend">Email data</param>
        /// <param name="subject">Subject</param>
        /// <param name="emailMessage">Message body</param>
        /// <param name="appointment">Optional appointment info</param>
        /// <param name="errorMessage">Error messages</param>
        private static void ProcessEmail(EmailToSendRecord emailToSend, string subject, string emailMessage,
                                         string appointment, string errorMessage)
        {
            using (var ctx = DataAccessFactory.CreateContext <IEmailDataOperations>())
            {
                ctx.BeginTransaction();

                if (errorMessage == null)
                {
                    ctx.InsertEmailSentAsync(new EmailSentRecord
                    {
                        Id          = emailToSend.Id,
                        FromAddr    = emailToSend.FromAddr,
                        FromName    = emailToSend.FromName,
                        ToAddr      = emailToSend.ToAddr,
                        Subject     = subject,
                        Message     = emailMessage,
                        Appointment = appointment,
                        SentUtc     = DateTime.Now
                    }).Wait();
                    ctx.DeleteEmailToSendAsync(emailToSend.Id).Wait();
                }
                else if (emailToSend.RetryCount < SmtpConfig.MaxRetry)
                {
                    emailToSend.LastError = errorMessage;
                    emailToSend.RetryCount++;
                    emailToSend.SendAfterUtc = DateTimeOffset.UtcNow.AddMinutes(SmtpConfig.RetryMinutes);
                    ctx.UpdateEmailToSendAsync(emailToSend).Wait();
                }
                else
                {
                    ctx.InsertEmailFailedAsync(new EmailFailedRecord
                    {
                        Id         = emailToSend.Id,
                        FromAddr   = emailToSend.FromAddr,
                        FromName   = emailToSend.FromName,
                        ToAddr     = emailToSend.ToAddr,
                        Subject    = subject,
                        Message    = emailMessage,
                        LastError  = errorMessage,
                        RetryCount = emailToSend.RetryCount,
                        FailedUtc  = DateTime.Now
                    }).Wait();
                    ctx.DeleteEmailToSendAsync(emailToSend.Id).Wait();
                }

                ctx.Complete();
            }
        }
        /// <summary>
        /// Inserts the specified user into the user database
        /// </summary>
        /// <param name="user">User information</param>
        public async Task InsertUserAsync(UserDto user)
        {
            Verify.NotNull(user, "user");
            Verify.RaiseWhenFailed();
            Verify.NotNullOrEmpty(user.Email, "user.Email");
            Verify.IsEmail(user.Email, "user.Email");
            Verify.NotNullOrEmpty(user.UserName, "user.UserName");
            Verify.NotNullOrEmpty(user.SecurityStamp, "user.SecurityStamp");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <ISubscriptionDataOperations>())
            {
                await ctx.InsertUserAsync(MapUser(user));
            }
        }
        /// <summary>
        /// Confirms the specified invitation code, and creates the appropriate user.
        /// </summary>
        /// <param name="invitationCode">Invitation code</param>
        public async Task <UserInvitationCoreDto> GetUserInvitationByCodeAsync(string invitationCode)
        {
            Verify.NotNullOrEmpty(invitationCode, "invitationCode");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <ISubscriptionDataOperations>())
            {
                var invitation = await ctx.GetUserInvitationByCodeAsync(invitationCode);

                return(invitation == null || invitation.ExpirationDateUtc < DateTimeOffset.UtcNow ||
                       invitation.State != UserInvitationState.SENT
                    ? null
                    : MapUserInvitation(invitation));
            }
        }
        /// <summary>
        /// Sets the state of the invitation with the specified id
        /// </summary>
        /// <param name="invitationId">Invitation ID</param>
        /// <param name="state">New invitation state</param>
        public async Task SetInvitationState(int invitationId, string state)
        {
            Verify.Require(state == UserInvitationState.SENT || state == UserInvitationState.ACTIVATED ||
                           state == UserInvitationState.REVOKED,
                           "state");
            using (var ctx = DataAccessFactory.CreateContext <ISubscriptionDataOperations>())
            {
                var invitation = await ctx.GetUserInvitationByIdAsync(invitationId);

                if (invitation == null)
                {
                    throw new UnknownInvitationIdException(invitationId);
                }
                invitation.State = state;
                await ctx.UpdateUserInvitationAsync(invitation);
            }
        }
        /// <summary>
        /// Inserts a new user account into the database
        /// </summary>
        /// <param name="account">Account information</param>
        /// <returns></returns>
        public async Task InsertUserAccountAsync(UserAccountDto account)
        {
            Verify.NotNull(account, "account");
            Verify.RaiseWhenFailed();
            Verify.NotNullOrEmpty(account.Provider, "account.Provider");
            Verify.NotNullOrEmpty(account.ProviderData, "account.ProviderData");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <ISubscriptionDataOperations>())
            {
                await ctx.InsertUserAccountAsync(new UserAccountRecord
                {
                    UserId       = account.UserId,
                    Provider     = account.Provider,
                    ProviderData = account.ProviderData
                });
            }
        }
 public void OtherExceptionsAreNotTranslated()
 {
     // --- Act
     try
     {
         using (var ctx = DataAccessFactory.CreateContext <ITestDataOperations>())
         {
             ctx.DummyCommand();
         }
     }
     catch (SqlException ex)
     {
         // --- Assert
         ex.ShouldBeOfType(typeof(SqlException));
         return;
     }
     Assert.Fail("This line should not be reached.");
 }
Example #21
0
        public void NonGenericCreateContextWorksAsExpected()
        {
            // --- Arrange
            var dc = new SqlDatabase(DB_CONN);
            dc.Execute("delete from [dbo].[Sample]");

            // --- Act
            List<SampleRecord> records;
            using (var ctx = (TestDataOperations)DataAccessFactory.CreateContext(typeof(ITestDataOperations)))
            {
                ctx.InsertSample(new SampleRecord { Id = 0, Name = "Haho" });
                ctx.InsertSample(new SampleRecord { Id = 0, Name = "Hello" });
                records = ctx.GetAllSamples();
            }

            // --- Assert
            records.ShouldHaveCountOf(2);
        }
Example #22
0
        /// <summary>
        /// Removes the specified dive log entry
        /// </summary>
        /// <param name="diveId">Dive log entry ID</param>
        public async Task RemoveDiveLogEntryAsync(int diveId)
        {
            using (var ctx = DataAccessFactory.CreateContext <IDiveLogDataAccessOperations>())
            {
                var diveRecord = await ctx.GetDiveLogByIdAsync(diveId);

                if (diveRecord == null)
                {
                    throw new DiveNotFoundException(diveId);
                }

                if (diveRecord.UserId != ServicedUserId)
                {
                    throw new NoPermissionToDiveLogException(diveRecord.Id, ServicedUserId, diveRecord.UserId);
                }

                await ctx.DeleteDiveLogEntryAsync(diveId);
            }
        }
Example #23
0
        /// <summary>
        /// Removes the specified locale
        /// </summary>
        /// <param name="code">Code of the locale</param>
        public void RemoveLocale(string code)
        {
            Verify.NotNullOrEmpty(code, "code");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <IConfigurationDataOperations>())
            {
                var localeInDb = ctx.GetByCode(code);
                if (localeInDb == null)
                {
                    throw new LocaleNotFoundException(code);
                }

                ctx.BeginTransaction();

                ctx.DeleteResourcesOfLocale(code);
                ctx.DeleteLocale(code);

                ctx.Complete();
            }
        }
        /// <summary>
        /// Create a new subscription with the specified data
        /// </summary>
        /// <param name="subscription">Subscription object</param>
        /// <param name="userId">User owning the subscription</param>
        /// <returns>The ID of the new subscription</returns>
        public async Task <int> CreateSubscriptionAsync(SubscriptionDto subscription, string userId)
        {
            Verify.NotNull(subscription, "subscription");
            Verify.RaiseWhenFailed();
            Verify.NotNullOrEmpty(subscription.SubscriberName, "subscription.SubscriberName");
            Verify.NotNullOrEmpty(subscription.PrimaryEmail, "subscription.PrimaryEmail");
            Verify.IsEmail(subscription.PrimaryEmail, "subscription.PrimaryEmail");
            Verify.NotNullOrEmpty(userId, "userId");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <ISubscriptionDataOperations>())
            {
                var userIdGuid = new Guid(userId);
                var userRecord = await ctx.GetUserByIdAsync(userIdGuid);

                if (userRecord == null)
                {
                    throw new InvalidOperationException(
                              string.Format("User with ID {0} have not been found in the database", userId));
                }
                await ctx.BeginTransactionAsync();

                var subscriptionRecord = MapSubscription(subscription);
                await ctx.InsertSubscriptionAsync(subscriptionRecord);

                await ctx.InsertSubscriptionOwnerAsync(new SubscriptionOwnerRecord
                {
                    SubscriptionId = subscriptionRecord.Id,
                    UserId         = userIdGuid,
                });

                userRecord.SubscriptionId  = subscriptionRecord.Id;
                userRecord.LastModifiedUtc = DateTimeOffset.UtcNow;
                await ctx.UpdateUserAsync(userRecord);

                await ctx.CompleteAsync();

                return(subscriptionRecord.Id);
            }
        }
Example #25
0
        /// <summary>
        /// Modifies an existing locale
        /// </summary>
        /// <param name="locale">Locale information</param>
        public void ModifyLocale(LocaleDto locale)
        {
            VerifyLocaleDto(locale);

            using (var ctx = DataAccessFactory.CreateContext <IConfigurationDataOperations>())
            {
                var localeInDb = ctx.GetByCode(locale.Code);
                if (localeInDb == null)
                {
                    throw new LocaleNotFoundException(locale.Code);
                }
                localeInDb.DisplayName = locale.DisplayName;
                try
                {
                    ctx.UpdateLocale(localeInDb);
                }
                catch (UniqueKeyViolationException)
                {
                    throw new DuplicatedLocaleDisplayNameException(locale.DisplayName);
                }
            }
        }
Example #26
0
        /// <summary>
        /// Registers a new dive log entry
        /// </summary>
        /// <param name="dive">The dive log entry to save</param>
        public async Task <int> RegisterDiveLogEntryAsync(DiveLogEntryDto dive)
        {
            ValidateDiveLogArgument(dive);
            Verify.Require(dive.Id == 0, "dive.Id");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <IDiveLogDataAccessOperations>())
            {
                var diveRecord = new DiveLogRecord
                {
                    UserId     = ServicedUserId,
                    Date       = dive.Date,
                    DiveSite   = dive.DiveSite,
                    Location   = dive.Location,
                    MaxDepth   = dive.MaxDepth,
                    BottomTime = dive.BottomTime,
                    Comment    = dive.Comment
                };
                await ctx.InsertDiveLogEntryAsync(diveRecord);

                return(diveRecord.Id);
            }
        }
Example #27
0
        /// <summary>
        /// Clones resources of a source locale into a destination locale
        /// </summary>
        /// <param name="request">Clone request object</param>
        /// <remarks>
        /// The request can define the default resource value. If this is null, the source value
        /// is copied, otherwise, this value. Setting OverrideExistingResource to true will overwrite
        /// any resource values already set.
        /// </remarks>
        public void CloneLocalizedResources(CloneLocalizedResourcesDto request)
        {
            Verify.NotNull(request, "request");
            Verify.RaiseWhenFailed();

            Verify.NotNullOrEmpty(request.BaseCode, "request.BaseCode");
            Verify.NotNullOrEmpty(request.TargetCode, "request.TargetCode");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <IConfigurationDataOperations>())
            {
                if (ctx.GetByCode(request.BaseCode) == null)
                {
                    throw new LocaleNotFoundException(request.BaseCode);
                }
                if (ctx.GetByCode(request.TargetCode) == null)
                {
                    throw new LocaleNotFoundException(request.TargetCode);
                }

                ctx.BeginTransaction();

                if (request.OverrideExistingResources)
                {
                    ctx.DeleteExistingSourceResourcesFromTarget(request.BaseCode, request.TargetCode);
                }
                if (request.DefaultResourceValue != null)
                {
                    ctx.CloneResourcesWithDefault(request.BaseCode, request.TargetCode, request.DefaultResourceValue);
                }
                else
                {
                    ctx.CloneResources(request.BaseCode, request.TargetCode);
                }
                ctx.Complete();
            }
        }
        /// <summary>
        /// Sends the email in the definition
        /// </summary>
        /// <param name="email">email definition</param>
        public void SendEmail(EmailDefinitionDto email)
        {
            Verify.NotNull(email, "email");
            Verify.RaiseWhenFailed();
            Verify.NotNullOrEmpty(email.FromAddr, "FromAddr");
            Verify.NotNullOrEmpty(email.ToAddr, "ToAddr");
            Verify.NotNullOrEmpty(email.TemplateType, "TemplateType");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <IEmailDataOperations>())
            {
                string parameters = null;
                if (email.Parameters != null)
                {
                    parameters = JsonConvert.SerializeObject(email.Parameters);
                }
                string appointment = null;
                if (email.Appointment != null)
                {
                    appointment = JsonConvert.SerializeObject(email.Appointment);
                }

                ctx.InsertEmailToSendAsync(new EmailToSendRecord
                {
                    FromAddr     = email.FromAddr,
                    FromName     = email.FromName,
                    ToAddr       = email.ToAddr,
                    TemplateType = email.TemplateType,
                    Parameters   = parameters,
                    Appointment  = appointment,
                    SendAfterUtc = email.SendAfterUtc,
                    RetryCount   = 0,
                    LastError    = null
                }).Wait();
            }
        }
Example #29
0
        /// <summary>
        /// Adds a new locale to the existing ones
        /// </summary>
        /// <param name="locale">Locale information</param>
        public void AddLocale(LocaleDto locale)
        {
            VerifyLocaleDto(locale);

            using (var ctx = DataAccessFactory.CreateContext <IConfigurationDataOperations>())
            {
                try
                {
                    ctx.InsertLocale(new LocaleRecord
                    {
                        Code        = locale.Code,
                        DisplayName = locale.DisplayName
                    });
                }
                catch (PrimaryKeyViolationException)
                {
                    throw new DuplicatedLocaleCodeException(locale.Code);
                }
                catch (UniqueKeyViolationException)
                {
                    throw new DuplicatedLocaleDisplayNameException(locale.DisplayName);
                }
            }
        }
        /// <summary>
        /// Sends an invitation to the specified user
        /// </summary>
        /// <param name="userInfo">Information about the invited user</param>
        public async Task InviteUserAsync(InviteUserDto userInfo)
        {
            Verify.NotNull(userInfo, "userInfo");
            Verify.RaiseWhenFailed();
            Verify.NotNullOrEmpty(userInfo.InvitedEmail, "userInfo.InvitedEmail");
            Verify.IsEmail(userInfo.InvitedEmail, "userInfo.InvitedEmail");
            Verify.NotNullOrEmpty(userInfo.InvitedUserName, "userInfo.InvitedUserName");
            Verify.RaiseWhenFailed();

            using (var ctx = DataAccessFactory.CreateContext <ISubscriptionDataOperations>())
            {
                var email = await ctx.GetUserByEmailAsync(userInfo.InvitedEmail);

                if (email != null)
                {
                    throw new EmailReservedException(userInfo.InvitedEmail);
                }

                var user = await ctx.GetUserByUserNameAsync(Principal.SubscriptionId, userInfo.InvitedUserName);

                if (user != null)
                {
                    throw new UserNameReservedException(userInfo.InvitedUserName);
                }

                var invitations = await ctx.GetUserInvitationByEmailAsync(userInfo.InvitedEmail);

                if (invitations.Any(i => i.State != UserInvitationState.REVOKED))
                {
                    throw new EmailAlreadyInvitedException(userInfo.InvitedEmail);
                }

                invitations = await ctx.GetUserInvitationByUserAsync(Principal.SubscriptionId, userInfo.InvitedUserName);

                if (invitations.Any(i => i.State != UserInvitationState.REVOKED))
                {
                    throw new UserAlreadyInvitedException(userInfo.InvitedEmail);
                }

                // --- Administer invitation
                var invitationCode = String.Format("{0:N}{1:N}{2:N}", Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid());
                await ctx.InsertUserInvitationAsync(new UserInvitationRecord
                {
                    InvitedUserName   = userInfo.InvitedUserName,
                    InvitedEmail      = userInfo.InvitedEmail,
                    InvitationCode    = invitationCode,
                    CreatedUtc        = DateTimeOffset.UtcNow,
                    ExpirationDateUtc = DateTimeOffset.UtcNow.AddHours(72),
                    SubscriptionId    = Principal.SubscriptionId,
                    UserId            = Principal.UserId,
                    LastModifiedUtc   = null,
                    State             = UserInvitationState.SENT,
                    Type = UserInvitationType.USER
                });

                // --- Send the email with the invitation link
                var invitationLink = string.Format("{0}/{1}", SubscriptionConfig.InvitationLinkPrefix, invitationCode);
                var sender         = ServiceManager.GetService <IEmailSender>();
                sender.SendEmail(SmtpConfig.EmailFromAddr, SmtpConfig.EmailFromName,
                                 new[] { userInfo.InvitedEmail },
                                 "SeemplectCloud invitation",
                                 "Click here to confirm your invitation: " + invitationLink);
            }
        }