// to allow the query and the methods there have to be a valid context / connectionstring and alarmclock for each existing object returned to the client
 internal static void ChecksOnContextAndClock(AuctionSiteContext db, IAlarmClock alarmClock)
 {
     if (db == null || alarmClock == null)
     {
         throw new InvalidOperationException("State of entity out of context, no data available");
     }
 }
Esempio n. 2
0
        // it returns the session if it is still valid
        public ISession GetSession(string sessionId)
        {
            if (sessionId == null)
            {
                throw new ArgumentNullException(nameof(sessionId), " is null");
            }

            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                if (!Db.Sites.Any(s => s.Name == Name))
                {
                    throw new InvalidOperationException("the site is deleted");
                }

                var sessionEntity = Db.Sessions.SingleOrDefault(s => s.Id == sessionId);
                if (sessionEntity == null)
                {
                    return(null);
                }
                var session = new Session(sessionEntity.ValidUntil, sessionEntity.Username, sessionEntity.SiteName)
                {
                    AlarmClock = AlarmClock,
                    Cs         = Cs
                };
                return(session.IsValid() ? session : null);
            }
        }
Esempio n. 3
0
        // if the site is still existing it will delete all the sessions
        public void CleanupSessions()
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                var siteEntity = Db.Sites.SingleOrDefault(s => s.Name == Name);
                if (null == siteEntity)
                {
                    throw new InvalidOperationException("the site is deleted");
                }

                var sessionsEntities = Db.Sessions.Where(s => s.SiteName == Name).Select(s => s).ToList();
                foreach (var s in sessionsEntities)
                {
                    var tmpSession = new Session(s.ValidUntil, s.Username, s.SiteName)
                    {
                        Cs = Cs, AlarmClock = AlarmClock
                    };
                    if (!tmpSession.IsValid())
                    {
                        tmpSession.Logout();
                    }
                }
                Db.SaveChanges();
            }
        }
Esempio n. 4
0
        // return the auctions if the site is still present
        public IEnumerable <IAuction> GetAuctions(bool onlyNotEnded)
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                if (!Db.Sites.Any(s => s.Name == Name))
                {
                    throw new InvalidOperationException("the site is deleted");
                }

                var auctionsEntities = Db.Auctions.Where(a => a.SiteName == Name).Select(a => a).ToList();

                var auctionsList = new List <Auction>();
                foreach (var a in auctionsEntities)
                {
                    var auction = new Auction(a.Id, a.Description, a.EndsOn, a.SiteName)
                    {
                        Cs = Cs, AlarmClock = AlarmClock
                    };
                    if (!onlyNotEnded || !auction.IsEnded())
                    {
                        auctionsList.Add(auction);
                    }
                }

                return(auctionsList);
            }
        }
Esempio n. 5
0
        // if all the constraints are respected it will create the user, otherwise it throws exception
        public void CreateUser(string username, string password)
        {
            ChecksOnUsernameAndPassword(username, password);

            if (Cs == null)
            {
                throw new InvalidOperationException("It was not possible to reach the Db");
            }
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                var siteEntity = Db.Sites.FirstOrDefault(s => s.Name == Name);
                if (null == siteEntity)
                {
                    throw new InvalidOperationException("the site is deleted");
                }
                if (Db.Users.Any(u => u.Username == username && u.SiteName == Name))
                {
                    throw new NameAlreadyInUseException(nameof(username), " of user already in use");
                }

                Db.Users.Add(new UserEntity(username, password, Name)
                {
                    Site = siteEntity
                });
                Db.SaveChanges();
            }
        }
        // after checks it creates a new site
        public void CreateSiteOnDb(string connectionString, string name, int timezone, int sessionExpirationTimeInSeconds,
                                   double minimumBidIncrement)
        {
            // constraints
            ChecksOnConnectionString(connectionString);
            ChecksOnName(name);
            if (Site.NotValidTimeZone(timezone) ||
                Site.NotValidSessionExpirationTime(sessionExpirationTimeInSeconds) ||
                Site.NotValidMinimumBiddingIncr(minimumBidIncrement))
            {
                throw new ArgumentOutOfRangeException();
            }

            //creation
            using (var context = new AuctionSiteContext(connectionString))
            {
                ChecksOnDbConnection(context);
                if (context.Sites.Any(s => s.Name == name))
                {
                    throw new NameAlreadyInUseException(nameof(name), " of site already in use");
                }
                context.Sites.Add(new SiteEntity(name, timezone, sessionExpirationTimeInSeconds, minimumBidIncrement));
                context.SaveChanges();
            }
        }
        // to initialize all the system
        public void Setup(string connectionString)
        {
            // constraints
            ChecksOnConnectionString(connectionString);

            // setup
            Database.Delete(connectionString); // dropping existing previous version, if any
            Database.SetInitializer(new DropCreateDatabaseAlways <AuctionSiteContext>());
            try
            {
                using (var context = new AuctionSiteContext(connectionString))
                {
                    context.Database.Create();
                    context.Sites.Create();
                    context.Users.Create();
                    context.Sessions.Create();
                    context.Auctions.Create();
                    context.SaveChanges();
                }
            }
            catch (Exception e)
            {
                throw new UnavailableDbException("error on DB Setup", e);
            }
        }
Esempio n. 8
0
        public IEnumerable <IAuction> WonAuctions()
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                if (!Db.Users.Any(u => u.Username == Username && u.SiteName == SiteName))
                {
                    throw new InvalidOperationException("the user does not exist anymore");
                }

                var auctionsEntities = Db.Auctions.Where(a => a.SiteName == SiteName && a.WinnerUsername == Username)
                                       .Select(a => a).ToList();
                var auctionList = new List <Auction>();

                foreach (var aEntity in auctionsEntities)
                {
                    var a = new Auction(aEntity.Id, aEntity.Description, aEntity.EndsOn, aEntity.SiteName)
                    {
                        Cs         = Cs,
                        AlarmClock = AlarmClock
                    };
                    if (a.IsEnded())
                    {
                        auctionList.Add(a);
                    }
                }

                return(auctionList);
            }
        }
Esempio n. 9
0
        // after the constraints it creates the auction, renews the the session, returns the auction
        public IAuction CreateAuction(string description, DateTime endsOn, double startingPrice)
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);

                if (description == null)
                {
                    throw new ArgumentNullException(nameof(description), "is null");
                }
                if (string.IsNullOrEmpty(description))
                {
                    throw new ArgumentException("is empty", nameof(description));
                }
                if (startingPrice < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(startingPrice), "is negative");
                }
                if (endsOn.CompareTo(AlarmClock.Now) < 0)
                {
                    throw new UnavailableTimeMachineException("endsOn precedes the current ISite's time");
                }
                if (!Db.Sessions.Any(s => s.Id == Id))
                {
                    throw new InvalidOperationException(nameof(Session) + " not consistent");
                }

                var siteEntity = Db.Sites.SingleOrDefault(site => site.Name == SiteName);
                if (siteEntity == null)
                {
                    throw new InvalidOperationException("the site does not exist anymore");
                }
                var sellerEntity = Db.Users.SingleOrDefault(s => s.SiteName == siteEntity.Name && s.Username == Username);
                if (sellerEntity == null)
                {
                    throw new InvalidOperationException("the user does not exist anymore");
                }

                var time          = siteEntity.SessionExpirationInSeconds;
                var auctionEntity =
                    new AuctionEntity(description, endsOn, startingPrice, Username, SiteName)
                {
                    Seller = sellerEntity
                };
                Db.Auctions.Add(auctionEntity);
                ResetTime(time);
                Db.SaveChanges();

                var auction = new Auction(auctionEntity.Id, auctionEntity.Description, auctionEntity.EndsOn,
                                          auctionEntity.SiteName)
                {
                    Cs = Cs, AlarmClock = AlarmClock
                };
                return(auction);
            }
        }
Esempio n. 10
0
        // delete every corresponded objects since it is the root of an aggregate
        public void Delete()
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                var siteEntity = Db.Sites.SingleOrDefault(s => s.Name == Name);
                if (null == siteEntity)
                {
                    throw new InvalidOperationException("the site is already deleted");
                }

                var sessionsEntities = Db.Sessions.Where(s => s.SiteName == Name).Select(s => s).ToList();
                // disposes the sessions' site and auctions' site
                foreach (var sEntity in sessionsEntities)
                {
                    var s = new Session(sEntity.ValidUntil, sEntity.Username, sEntity.SiteName)
                    {
                        Cs         = Cs,
                        AlarmClock = AlarmClock
                    };
                    s.Logout();
                }

                var auctionsEntities = Db.Auctions.Where(a => a.SiteName == Name).Select(a => a).ToList();
                foreach (var aEntity in auctionsEntities)
                {
                    var a = new Auction(aEntity.Id, aEntity.Description, aEntity.EndsOn, aEntity.SiteName)
                    {
                        Cs         = Cs,
                        AlarmClock = AlarmClock
                    };
                    a.Delete();
                }

                // disposes the users' site
                var usersEntities = Db.Users.Where(u => u.SiteName == Name).Select(u => u).ToList();
                foreach (var uEntity in usersEntities)
                {
                    var u = new User(uEntity.Username, uEntity.SiteName)
                    {
                        Cs = Cs, AlarmClock = AlarmClock
                    };
                    u.Delete();
                }
            }
            using (var Db = new AuctionSiteContext(Cs)) {
                var siteEntity = Db.Sites.SingleOrDefault(s => s.Name == Name);
                if (null == siteEntity)
                {
                    throw new InvalidOperationException("the site is already deleted");
                }
                Db.Sites.Remove(siteEntity);
                Db.SaveChanges();
            }
        }
        public IEnumerable <string> GetSiteNames(string connectionString)
        {
            // constraints
            ChecksOnConnectionString(connectionString);

            // attempt to Load Site and get each site name
            using (var context = new AuctionSiteContext(connectionString))
            {
                ChecksOnDbConnection(context);
                var sites = context.Sites.Select(s => s.Name).ToList();
                return(sites);
            }
        }
Esempio n. 12
0
 double IAuction.CurrentPrice()
 {
     SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
     using (var Db = new AuctionSiteContext(Cs))
     {
         SiteFactory.ChecksOnDbConnection(Db);
         var auctionEntity = Db.Auctions.SingleOrDefault(a => a.Id == Id && a.SiteName == SiteName);
         if (auctionEntity == null)
         {
             throw new InvalidOperationException("the auction does not exist anymore");
         }
         return(auctionEntity.CurrentPrice);
     }
 }
Esempio n. 13
0
 // to checks if it is valid that is correctly present on the db and not expired
 public bool IsValid()
 {
     // controllo che sia correttamente creata e presente sul DB
     SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
     using (var Db = new AuctionSiteContext(Cs))
     {
         SiteFactory.ChecksOnDbConnection(Db);
         var sessionEntity = Db.Sessions.SingleOrDefault(s => s.Id == Id);
         if (null == sessionEntity) // sessione cancellata, logout effettuato
         {
             return(false);
         }
         return(sessionEntity.ValidUntil.CompareTo(AlarmClock.Now) > 0); // Ritorna maggiore di zero se la scadenza è dopo l'ora attuale
     }
 }
Esempio n. 14
0
        public void Delete()
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                var auctionEntity = Db.Auctions.SingleOrDefault(a => a.Id == Id && a.SiteName == SiteName);
                if (auctionEntity == null)
                {
                    throw new InvalidOperationException("the auction does not exist anymore");
                }

                Db.Auctions.Remove(auctionEntity);
                Db.SaveChanges();
            }
        }
Esempio n. 15
0
 // to reset the expiration time
 internal void ResetTime(int seconds)
 {
     SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
     using (var Db = new AuctionSiteContext(Cs))
     {
         SiteFactory.ChecksOnDbConnection(Db);
         var sessionEntity = Db.Sessions.SingleOrDefault(s => s.Id == Id);
         if (sessionEntity == null)
         {
             throw new InvalidOperationException("the session does not exist anymore");
         }
         sessionEntity.ValidUntil = AlarmClock.Now.AddSeconds(seconds);
         ValidUntil = sessionEntity.ValidUntil;
         Db.SaveChanges();
     }
 }
 internal static void ChecksOnDbConnection(AuctionSiteContext db)
 {
     try
     {
         db.Database.Connection.Open();
         db.Database.Connection.Close();
     }
     catch (DbException e)
     {
         throw new UnavailableDbException("Invalid context, it was not possible to connect to the DB", e);
     }
     catch (InvalidOperationException e)
     {
         throw new UnavailableDbException("Invalid context, it was not possible to connect to the DB", e);
     }
 }
Esempio n. 17
0
        // to end the session if it is still present
        public void Logout()
        {
            if (Cs == null)
            {
                throw new InvalidOperationException("State of entity out of context, no data available");
            }
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                var sessionEntity = Db.Sessions.SingleOrDefault(s => s.Id == Id);
                if (null == sessionEntity) // sessione cancellata, logout effettuato
                {
                    throw new InvalidOperationException(nameof(SessionEntity) + " not consistent");
                }

                Db.Sessions.Remove(sessionEntity);
                Db.SaveChanges();
            }
        }
Esempio n. 18
0
        // it allows to sign in if possible. If a session already existing it will be renewed in each cases otherwise a new one is created.
        public ISession Login(string username, string password)
        {
            ChecksOnUsernameAndPassword(username, password);
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                if (!Db.Sites.Any(s => s.Name == Name))
                {
                    throw new InvalidOperationException("the site is deleted");
                }
                var userEntity = Db.Users.SingleOrDefault(u => u.Username == username && u.Password == password && u.SiteName == Name);
                if (null == userEntity) // l'utente non esiste o dati sbagliati
                {
                    return(null);
                }

                var sessionEntity = Db.Sessions.SingleOrDefault(s => s.Id == Name + username);
                var session       = new Session(AlarmClock.Now.AddSeconds(SessionExpirationInSeconds), username, Name)
                {
                    AlarmClock = AlarmClock,
                    Cs         = Cs
                };

                if (sessionEntity == null) // l'utente esiste e non ha una sessione attiva
                {
                    // new session
                    sessionEntity = new SessionEntity(AlarmClock.Now.AddSeconds(SessionExpirationInSeconds), username, Name)
                    {
                        User = userEntity
                    };
                    Db.Sessions.Add(sessionEntity);
                }
                else
                {
                    session.ResetTime(SessionExpirationInSeconds); // l'utente esiste e ha una sessione valida oppure no, si rinnova comunque
                }
                Db.SaveChanges();
                return(session);
            }
        }
        // after checks it loads an existing site and returns it to the client
        public ISite LoadSite(string connectionString, string name, IAlarmClock alarmClock)
        {
            // constraints
            ChecksOnConnectionString(connectionString);
            ChecksOnName(name);
            if (alarmClock == null)
            {
                throw new ArgumentNullException(nameof(alarmClock), " is null");
            }

            // attempt to Load Site
            using (var context = new AuctionSiteContext(connectionString))
            {
                ChecksOnDbConnection(context);
                var siteEntity = context.Sites.Find(name); // if more than one, it throws InvalidOperationException which is okay

                if (siteEntity == null)
                {
                    throw new InexistentNameException(nameof(name), " corresponding site is not present in the DB");
                }
                if (siteEntity.Timezone != alarmClock.Timezone)
                {
                    throw new ArgumentException("timezone is not equal to the one of the site", nameof(alarmClock));
                }

                // "injection" of the alarm clock and  the context to make possible the queries inside ISite's methods
                var site = new Site(siteEntity.Name, siteEntity.Timezone, siteEntity.SessionExpirationInSeconds,
                                    siteEntity.MinimumBidIncrement)
                {
                    AlarmClock = alarmClock, Cs = connectionString
                };

                var alarm    = alarmClock.InstantiateAlarm(CleanUpTime);
                var siteName = site.Name;
                // metodo anonimo con due riferimenti per evitare di mantenere contesto aperto
                alarm.RingingEvent += delegate { MakeCleanUpSessionIfExists(alarmClock, alarm, connectionString, siteName); };

                return(site);
            }
        }
        public int GetTheTimezoneOf(string connectionString, string name)
        {
            // constraints
            ChecksOnConnectionString(connectionString);
            ChecksOnName(name);

            // attempt to Load Site and get its timezone
            int timezone;

            using (var context = new AuctionSiteContext(connectionString))
            {
                ChecksOnDbConnection(context);
                var site = context.Sites.Find(name); // if more than one, it throws InvalidOperationException which is okay
                if (site == null)
                {
                    throw new InexistentNameException(nameof(name), " corresponding site is not present in the DB");
                }
                timezone = site.Timezone;
            }

            return(timezone);
        }
Esempio n. 21
0
        // it returns all the sessions if the site is not deleted
        public IEnumerable <ISession> GetSessions()
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                if (!Db.Sites.Any(s => s.Name == Name))
                {
                    throw new InvalidOperationException("the site is deleted");
                }

                var sessionsEntities = Db.Sessions.Where(s => s.SiteName == Name).Select(s => s).ToList();
                var sessions         = new List <Session>();
                foreach (var s in sessionsEntities)
                {
                    sessions.Add(new Session(s.ValidUntil, s.Username, s.SiteName)
                    {
                        AlarmClock = AlarmClock, Cs = Cs
                    });
                }
                return(sessions);
            }
        }
        // auxiliary function to invoke cleanUpSessions with all the args necessary
        internal void MakeCleanUpSessionIfExists(IAlarmClock alarmClock, IAlarm alarm, string cs, string siteName)
        {
            ChecksOnName(siteName);
            using (var context = new AuctionSiteContext(cs))
            {
                ChecksOnDbConnection(context);
                var siteEntity = context.Sites.Find(siteName); // if more than one, it throws InvalidOperationException which is okay

                if (siteEntity == null)
                {
                    alarm.Dispose(); // prova a vedere se ci sono problemi
                }
                else
                {
                    var site = new Site(siteEntity.Name, siteEntity.Timezone, siteEntity.SessionExpirationInSeconds,
                                        siteEntity.MinimumBidIncrement)
                    {
                        Cs = cs, AlarmClock = alarmClock
                    };
                    site.CleanupSessions();
                }
            }
        }
Esempio n. 23
0
        // it returns all the users if the site is not deleted
        public IEnumerable <IUser> GetUsers()
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                if (!Db.Sites.Any(s => s.Name == Name))
                {
                    throw new InvalidOperationException("the site is deleted");
                }

                var usersEntities = Db.Users.Where(s => s.SiteName == Name).ToList();
                var users         = new List <User>();
                foreach (var u in usersEntities)
                {
                    users.Add(new User(u.Username, u.SiteName)
                    {
                        AlarmClock = AlarmClock, Cs = Cs
                    });
                }

                return(users);
            }
        }
Esempio n. 24
0
        public IUser CurrentWinner()
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                var auctionEntity = Db.Auctions.SingleOrDefault(a => a.Id == Id && a.SiteName == SiteName);
                if (auctionEntity == null)
                {
                    throw new InvalidOperationException("the auction does not exist anymore");
                }

                if (null == auctionEntity.WinnerUsername)
                {
                    return(null);
                }

                var userEntity = Db.Users.SingleOrDefault(u => u.Username == auctionEntity.WinnerUsername && u.SiteName == SiteName);
                return(null == userEntity ? null : new User(userEntity.Username, userEntity.SiteName)
                {
                    Cs = Cs, AlarmClock = AlarmClock
                });
            }
        }
Esempio n. 25
0
        public void Delete()
        {
            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                var userEntity = Db.Users.SingleOrDefault(u => u.Username == Username && u.SiteName == SiteName);
                if (null == userEntity)
                {
                    throw new InvalidOperationException("the user does not exist anymore");
                }

                // owner of auctions not ended yet, winner of auctions not ended yet -> IOE exception
                var anySellerAuctionsEntities = Db.Auctions.Where(a => a.SellerUsername == Username && a.SiteName == SiteName);
                var anySellerAuctions         = new List <Auction>();
                var anyWinnerAuctionsEntities = Db.Auctions.Where(a => a.WinnerUsername == Username && a.SiteName == SiteName);
                var deletable = true;
                foreach (var aEntity in anySellerAuctionsEntities)
                {
                    var a = new Auction(aEntity.Id, aEntity.Description, aEntity.EndsOn, aEntity.SiteName)
                    {
                        Cs = Cs, AlarmClock = AlarmClock
                    };
                    anySellerAuctions.Add(a);
                    if (a.IsEnded())
                    {
                        continue;
                    }
                    deletable = false;
                    break;
                }
                if (!deletable)
                {
                    throw new InvalidOperationException("the user's auction(s) is not ended yet");
                }
                foreach (var aEntity in anyWinnerAuctionsEntities)
                {
                    var a = new Auction(aEntity.Id, aEntity.Description, aEntity.EndsOn, aEntity.SiteName)
                    {
                        Cs = Cs, AlarmClock = AlarmClock
                    };
                    if (a.IsEnded())
                    {
                        continue;
                    }
                    deletable = false;
                    break;
                }
                if (!deletable)
                {
                    throw new InvalidOperationException("the user is winning an auction not ended yet");
                }

                // ended owned auctions are disposed, ended won auctions are updated
                foreach (var a in anySellerAuctions)
                {
                    a.Delete();
                }

                foreach (var a in anyWinnerAuctionsEntities)
                {
                    a.WinnerUsername = null;
                }

                var sessions = Db.Sessions.Where(s => s.SiteName == SiteName && s.Username == Username).Select(s => s);
                foreach (var s in sessions)
                {
                    Db.Sessions.Remove(s);
                }


                Db.SaveChanges();
            }
            using (var Db = new AuctionSiteContext(Cs))
            {
                var userEntity = Db.Users.SingleOrDefault(u => u.Username == Username && u.SiteName == SiteName);
                if (null == userEntity)
                {
                    throw new InvalidOperationException("the user does not exist anymore");
                }
                // the user is removed and the Db and AlarmClock must be null
                Db.Users.Remove(userEntity);
                Db.SaveChanges();
            }
        }
Esempio n. 26
0
        public bool BidOnAuction(ISession session, double offer)
        {
            // constraints, many checks on the args and the corresponding permanent objects
            if (null == session)
            {
                throw new ArgumentNullException(nameof(session), "is null");
            }
            if (offer < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(offer), "offer is negative");
            }

            SiteFactory.ChecksOnCsAndClock(Cs, AlarmClock);
            using (var Db = new AuctionSiteContext(Cs))
            {
                SiteFactory.ChecksOnDbConnection(Db);
                if (!(session is Session))
                {
                    throw new ArgumentException("the session is not valid: it is out of the context");
                }
                var s = (Session)session;
                s.Cs         = Cs;
                s.AlarmClock = AlarmClock;

                var sessionEntity = Db.Sessions.SingleOrDefault(sE => sE.Id == s.Id);
                if (null == sessionEntity)
                {
                    throw new ArgumentException("the session is not valid: it does not exist anymore");
                }

                var siteEntity = Db.Sites.SingleOrDefault(site => site.Name == sessionEntity.SiteName);
                if (siteEntity == null)
                {
                    throw new InvalidOperationException("the site does not exist anymore");
                }

                if (!Db.Users.Any(u => u.Username == sessionEntity.Username && u.SiteName == sessionEntity.SiteName))
                {
                    throw new InvalidOperationException("the user does not exist anymore");
                }

                var auctionEntity = Db.Auctions.SingleOrDefault(a => a.Id == Id && a.SiteName == SiteName);
                if (null == auctionEntity)
                {
                    throw new InvalidOperationException("the auction does not exist anymore");
                }
                if (IsEnded())
                {
                    throw new InvalidOperationException("the auction is already closed");
                }

                ChecksOnSession(s, auctionEntity.SiteName);

                // the session is valid, the bid too
                var minimum      = siteEntity.MinimumBidIncrement;
                var time         = siteEntity.SessionExpirationInSeconds;
                var winning      = auctionEntity.WinnerUsername;
                var firstBid     = auctionEntity.FirstBid;
                var currentPrice = auctionEntity.CurrentPrice;
                var highestPrice = auctionEntity.HighestPrice;


                s.ResetTime(time);
                Db.SaveChanges();

                if (BidIsNotAccepted(s.Username, winning, firstBid, offer, minimum, currentPrice, highestPrice))
                {
                    return(false);
                }

                if (!firstBid && winning != s.Username && offer <= highestPrice)
                {
                    currentPrice = offer + minimum < highestPrice ? offer + minimum : highestPrice;
                    auctionEntity.CurrentPrice = currentPrice;
                }
                else // a new major bidder is coming!
                {
                    if (!firstBid && winning != s.Username)
                    {
                        currentPrice = offer < highestPrice + minimum ? offer : highestPrice + minimum;
                        auctionEntity.CurrentPrice = currentPrice;
                    }
                    auctionEntity.HighestPrice   = offer;
                    auctionEntity.WinnerUsername = s.Username;
                }
                auctionEntity.FirstBid = false;
                Db.SaveChanges();
                return(true);
            }
        }