public User CreateAccount(string name, string nickname, string password, string email, string description, out bool badName, out bool badEmail)
        {
            badName = false;
            badEmail = false;

            using (var ctx = new GitCandyContext())
            //using (TransactionScope transaction = new TransactionScope()) // I don't know why Sqlite not support for TransactionScope
            {
                try
                {
                    var list = ctx.Users.Where(s => s.Name == name || s.Email == email).ToList();
                    badName = list.Any(s => string.Equals(s.Name, name, StringComparison.OrdinalIgnoreCase));
                    badEmail = list.Any(s => string.Equals(s.Email, email, StringComparison.OrdinalIgnoreCase));

                    if (badName || badEmail)
                        return null;

                    var user = new User
                    {
                        Name = name,
                        Nickname = nickname,
                        Email = email,
                        PasswordVersion = -1,
                        Password = "",
                        Description = description,
                        CreationDate = DateTime.UtcNow,
                    };
                    ctx.Users.Add(user);
                    ctx.SaveChanges();

                    using (var pp = PasswordProviderPool.Take())
                    {
                        user.PasswordVersion = pp.Version;
                        user.Password = pp.Compute(user.ID, name, password);
                    }
                    ctx.SaveChanges();

                    //transaction.Complete();
                    return user;
                }
                catch
                {
                    return null;
                }
            }
        }
        public Repository Create(RepositoryModel model, long managerID, out bool badName)
        {
            using (var ctx = new GitCandyContext())
            //using (TransactionScope transaction = new TransactionScope())
            {
                badName = ctx.Repositories.Any(s => s.Name == model.Name);
                if (badName)
                    return null;

                var repo = new Repository
                {
                    Name = model.Name,
                    Description = model.Description,
                    CreationDate = DateTime.UtcNow,
                    IsPrivate = model.IsPrivate,
                    AllowAnonymousRead = model.AllowAnonymousRead,
                    AllowAnonymousWrite = model.AllowAnonymousWrite,
                };
                ctx.Repositories.Add(repo);
                ctx.SaveChanges();

                if (managerID > 0)
                {
                    repo.UserRepositoryRoles.Add(new UserRepositoryRole
                    {
                        Repository = repo,
                        UserID = managerID,
                        IsOwner = true,
                        AllowRead = true,
                        AllowWrite = true
                    });
                }
                ctx.SaveChanges();

                //transaction.Complete();
                return repo;
            }
        }
        public Team CreateTeam(string name, string description, long managerID, out bool badName)
        {
            badName = false;

            using (var ctx = new GitCandyContext())
            //using (TransactionScope transaction = new TransactionScope())
            {
                try
                {
                    badName = ctx.Teams.Count(s => s.Name == name) != 0;

                    if (badName)
                        return null;

                    var team = new Team
                    {
                        Name = name,
                        Description = description,
                        CreationDate = DateTime.UtcNow,
                    };
                    ctx.Teams.Add(team);

                    if (managerID > 0)
                    {
                        team.UserTeamRoles.Add(new UserTeamRole { Team = team, UserID = managerID, IsAdministrator = true });
                    }
                    ctx.SaveChanges();

                    //transaction.Complete();
                    return team;
                }
                catch
                {
                    return null;
                }
            }
        }
 public bool UpdateTeam(TeamModel model)
 {
     using (var ctx = new GitCandyContext())
     {
         var team = ctx.Teams.FirstOrDefault(s => s.Name == model.Name);
         if (team != null)
         {
             team.Description = model.Description;
             ctx.SaveChanges();
             return true;
         }
         return false;
     }
 }
 public void SetAuthorizationAsInvalid(Guid authCode)
 {
     using (var ctx = new GitCandyContext())
     {
         var auth = ctx.AuthorizationLogs.FirstOrDefault(s => s.AuthCode == authCode);
         if (auth != null)
         {
             auth.IsValid = false;
             ctx.SaveChanges();
         }
     }
 }
 public void DeleteUser(string name)
 {
     using (var ctx = new GitCandyContext())
     {
         var user = ctx.Users.FirstOrDefault(s => s.Name == name);
         if (user != null)
         {
             user.UserTeamRoles.Clear();
             user.UserRepositoryRoles.Clear();
             user.AuthorizationLogs.Clear();
             ctx.Users.Remove(user);
             ctx.SaveChanges();
         }
     }
 }
 public AuthorizationLog CreateAuthorization(long userID, DateTime expires, string ip)
 {
     using (var ctx = new GitCandyContext())
     {
         var auth = new AuthorizationLog
         {
             AuthCode = Guid.NewGuid(),
             UserID = userID,
             IssueDate = DateTime.Now,
             Expires = expires,
             IssueIp = ip,
             LastIp = ip,
             IsValid = true,
         };
         ctx.AuthorizationLogs.Add(auth);
         ctx.SaveChanges();
         return auth;
     }
 }
 public void UpdateAuthorization(Guid authCode, DateTime expires, string lastIp)
 {
     using (var ctx = new GitCandyContext())
     {
         var auth = ctx.AuthorizationLogs.FirstOrDefault(s => s.AuthCode == authCode);
         if (auth != null)
         {
             auth.Expires = expires;
             auth.LastIp = lastIp;
             ctx.SaveChanges();
         }
     }
 }
        public bool TeamUserSetAdministrator(string teamname, string username, bool isAdmin)
        {
            using (var ctx = new GitCandyContext())
            {
                var role = ctx.UserTeamRoles.FirstOrDefault(s => s.Team.Name == teamname && s.User.Name == username);
                if (role == null)
                    return false;

                role.IsAdministrator = isAdmin;

                ctx.SaveChanges();
                return true;
            }
        }
        public bool RepositoryRemoveTeam(string reponame, string teamname)
        {
            using (var ctx = new GitCandyContext())
            {
                var role = ctx.TeamRepositoryRoles.FirstOrDefault(s => s.Repository.Name == reponame && s.Team.Name == teamname);
                if (role == null)
                    return false;

                ctx.TeamRepositoryRoles.Remove(role);
                ctx.SaveChanges();
                return true;
            }
        }
 public User Login(string id, string password)
 {
     using (var ctx = new GitCandyContext())
     {
         var user = ctx.Users.FirstOrDefault(s => s.Name == id || s.Email == id);
         if (user != null)
         {
             using (var pp1 = PasswordProviderPool.Take(user.PasswordVersion))
                 if (user.Password == pp1.Compute(user.ID, user.Name, password))
                 {
                     if (user.PasswordVersion != PasswordProviderPool.LastVersion)
                         using (var pp2 = PasswordProviderPool.Take())
                         {
                             user.Password = pp2.Compute(user.ID, user.Name, password);
                             user.PasswordVersion = pp2.Version;
                             ctx.SaveChanges();
                         }
                     return user;
                 }
         }
         return null;
     }
 }
        public void SetPassword(string name, string newPassword)
        {
            using (var ctx = new GitCandyContext())
            {
                var user = ctx.Users.FirstOrDefault(s => s.Name == name);
                if (user != null)
                {
                    using (var pp = PasswordProviderPool.Take())
                    {
                        user.Password = pp.Compute(user.ID, user.Name, newPassword);
                        user.PasswordVersion = pp.Version;
                    }

                    var auths = ctx.AuthorizationLogs.Where(s => s.UserID == user.ID);
                    foreach (var auth in auths)
                    {
                        auth.IsValid = false;
                    }
                    ctx.SaveChanges();
                }
            }
        }
        public bool Update(RepositoryModel model)
        {
            using (var ctx = new GitCandyContext())
            {
                var repo = ctx.Repositories.FirstOrDefault(s => s.Name == model.Name);
                if (repo != null)
                {
                    repo.IsPrivate = model.IsPrivate;
                    repo.AllowAnonymousRead = model.AllowAnonymousRead;
                    repo.AllowAnonymousWrite = model.AllowAnonymousWrite;
                    repo.Description = model.Description;

                    ctx.SaveChanges();
                    return true;
                }
                return false;
            }
        }
 public void Delete(string name)
 {
     using (var ctx = new GitCandyContext())
     {
         var repo = ctx.Repositories.FirstOrDefault(s => s.Name == name);
         if (repo != null)
         {
             repo.TeamRepositoryRoles.Clear();
             repo.UserRepositoryRoles.Clear();
             ctx.Repositories.Remove(repo);
             ctx.SaveChanges();
         }
     }
 }
        public bool RepositoryTeamSetValue(string reponame, string teamname, string field, bool value)
        {
            using (var ctx = new GitCandyContext())
            {
                var role = ctx.TeamRepositoryRoles.FirstOrDefault(s => s.Repository.Name == reponame && s.Team.Name == teamname);
                if (role == null)
                    return false;

                if (field == "read")
                    role.AllowRead = value;
                else if (field == "write")
                    role.AllowWrite = value;
                else
                    return false;

                ctx.SaveChanges();
                return true;
            }
        }
        public bool TeamAddUser(string teamname, string username)
        {
            using (var ctx = new GitCandyContext())
            {
                var pair = (from t in ctx.Teams
                            from u in ctx.Users
                            where t.Name == teamname && u.Name == username
                                && t.UserTeamRoles.All(r => r.UserID != u.ID)
                            select new { TeamID = t.ID, UserID = u.ID })
                            .FirstOrDefault();
                if (pair == null)
                    return false;

                ctx.UserTeamRoles.Add(new UserTeamRole { TeamID = pair.TeamID, UserID = pair.UserID, IsAdministrator = false });

                ctx.SaveChanges();
                return true;
            }
        }
        public UserRepositoryRole RepositoryAddUser(string reponame, string username)
        {
            using (var ctx = new GitCandyContext())
            {
                var pair = (from r in ctx.Repositories
                            from u in ctx.Users
                            where r.Name == reponame && u.Name == username
                                && r.UserRepositoryRoles.All(s => s.User.Name != username)
                            select new { RepoID = r.ID, UserID = u.ID })
                            .FirstOrDefault();
                if (pair == null)
                    return null;

                var role = new UserRepositoryRole
                {
                    RepositoryID = pair.RepoID,
                    UserID = pair.UserID,
                    AllowRead = true,
                    AllowWrite = true,
                    IsOwner = false,
                };
                ctx.UserRepositoryRoles.Add(role);
                ctx.SaveChanges();
                return role;
            }
        }
        public bool TeamRemoveUser(string teamname, string username)
        {
            using (var ctx = new GitCandyContext())
            {
                var role = ctx.UserTeamRoles.FirstOrDefault(s => s.Team.Name == teamname && s.User.Name == username);
                if (role == null)
                    return false;

                ctx.UserTeamRoles.Remove(role);

                ctx.SaveChanges();
                return true;
            }
        }
        public TeamRepositoryRole RepositoryAddTeam(string reponame, string teamname)
        {
            using (var ctx = new GitCandyContext())
            {
                var pair = (from r in ctx.Repositories
                            from t in ctx.Teams
                            where r.Name == reponame && t.Name == teamname
                                && r.TeamRepositoryRoles.All(s => s.Team.Name != teamname)
                            select new { RepoID = r.ID, TeamID = t.ID })
                            .FirstOrDefault();
                if (pair == null)
                    return null;

                var role = new TeamRepositoryRole
                {
                    RepositoryID = pair.RepoID,
                    TeamID = pair.TeamID,
                    AllowRead = true,
                    AllowWrite = true,
                };
                ctx.TeamRepositoryRoles.Add(role);
                ctx.SaveChanges();
                return role;
            }
        }
 public void DeleteTeam(string name)
 {
     using (var ctx = new GitCandyContext())
     {
         var team = ctx.Teams.FirstOrDefault(s => s.Name == name);
         if (team != null)
         {
             team.UserTeamRoles.Clear();
             team.TeamRepositoryRoles.Clear();
             ctx.Teams.Remove(team);
             ctx.SaveChanges();
         }
     }
 }
        public bool UpdateUser(UserModel model)
        {
            using (var ctx = new GitCandyContext())
            {
                var user = ctx.Users.FirstOrDefault(s => s.Name == model.Name);
                if (user != null)
                {
                    user.Nickname = model.Nickname;
                    user.Email = model.Email;
                    user.Description = model.Description;
                    user.IsSystemAdministrator = model.IsSystemAdministrator;

                    ctx.SaveChanges();
                    return true;
                }
                return false;
            }
        }