예제 #1
0
        public void DeleteAd(string id, string authorEmail)
        {
            var db       = DbContextControl.GetNew();
            Ad  toDelete = new Ad {
                Id = id
            };

            toDelete.Author = UserControl.GetInstance().GetUser(authorEmail);//TODO:change

            db.Ads.Attach(toDelete);

            Price price = toDelete.Price;

            if (price != null)
            {
                db.Prices.Attach(toDelete.Price);
                db.Prices.Remove(price);
            }

            var comments = db.Comments.Where(c => c.ReplyId == id);

            db.Comments.RemoveRange(comments);

            db.Ads.Remove(toDelete);

            //db.Entry(toDelete).State = EntityState.Deleted;
            db.SaveChanges();
        }
예제 #2
0
        public Comment PostComment(string adId, string content, string authorEmail)
        {
            var db = DbContextControl.GetNew();

            var comment = new Comment {
                Content     = content,
                DatePosted  = DateTime.Now,
                Indent      = 0,
                ImageSource = null,
                LastEdited  = DateTime.Now,
                ReplyId     = adId,
            };

            //Find a user and attach him to the DB context
            var authorFull = db.Users.Attach(
                db.Users.FirstOrDefault(u => u.Email == authorEmail));

            //Attach the user to the Ad
            comment.Author = authorFull;

            db.Comments.Add(comment);
            db.SaveChanges();

            return(comment);
        }
예제 #3
0
        /// <summary>
        /// Unreserves a user's ad, doesn't refund reservations.
        /// </summary>
        /// <param name="id">Id of the Ad</param>
        /// <param name="userEmail">Email of the user</param>
        /// <exception cref="PostNotFoundException"></exception>
        /// <exception cref="UserNotFoundException"></exception>
        /// <exception cref="ArgumentException">If ad is not reserved or the author is different.</exception>
        public void UnreserveAd(string id, string userEmail)
        {
            Ad   ad   = GetAd(id);
            User user = UserControl.GetInstance().GetUser(userEmail);

            if (ad.ReservedBy == null)
            {
                throw new ArgumentException("Can not unreserve: Ad is not reserved.");
            }

            if (user.Id != ad.ReservedBy.Id)
            {
                throw new ArgumentException("Users can not unreserve other people's ads.");
            }

            var db = DbContextControl.GetNew();

            //Get ad into context
            db.Ads.Attach(ad);
            db.Entry(ad).State = EntityState.Modified;

            ad.ReservedBy = null;

            db.SaveChanges();
        }
예제 #4
0
        public void DeleteReplies(string replyId)
        {
            var db = DbContextControl.GetNew();

            var comments = db.Comments.Where(c => c.ReplyId == replyId);

            db.Comments.RemoveRange(comments);
            db.SaveChanges();
        }
예제 #5
0
        public void BuyBoosts(string email)
        {
            var  db   = DbContextControl.GetNew();
            User user = db.Users.FirstOrDefault(u => u.Email == email);

            user = db.Users.Attach(user);
            db.Entry(user).Property("Boosts").IsModified = true;
            user.Boosts += 5;
            db.SaveChanges();
        }
예제 #6
0
        /// <summary>
        /// A VERY expensive operation that searches through ad content. Use with caution.
        /// </summary>
        /// <param name="skip">Skip amount of ads (for paging)</param>
        /// <param name="amount">Take amount of ads (for paging)</param>
        /// <param name="location">General location of ad</param>
        /// <param name="searchQuery">A search query, like a few words that describe what is searched</param>
        /// <returns>A page of ads that match the criteria.</returns>
        public IList <Ad> FindAds(int skip, int amount, string location, string searchQuery, AdType type = AdType.All)
        {
            //Throttle amount of ads found, to reduce load
            if (amount > Throttle)
            {
                amount = Throttle;
            }

            //Get a DB context
            var db = DbContextControl.GetNew();

            //Get all locations that the ad is within
            IList <string> possibleLocations;

            try
            {
                possibleLocations = GetPossibleLocationNames(location);
            }
            catch (LocationNotFoundException)
            {
                possibleLocations = new List <string>();
            }

            //Get the keywords for searching in ad content
            var keywords = searchQuery.GetKeywords();

            //Delimit to ads that are within a location, use this as base for the search query
            //Also order by date posted
            IQueryable <Ad> query = db.Ads.Include(a => a.Location);

            //A complex and heavy SQL query to find the searchQuery string within ad titles, contents and categories
            //We are using the keywords list instead of the searchQuery directly
            query = (from ad in query
                     where (type == AdType.All || ad.Type == type) && //Check type, all or one
                     (possibleLocations.Count == 0 || //Check location, ignore if none apply
                      possibleLocations.Any(loc => ad.Location.Name == loc)) &&
                     (keywords.Count == 0 || //Check for keywords, ignore if none apply
                      keywords.Any(kw => ad.Title.ToLower().Contains(kw) ||
                                   ad.Content.ToLower().Contains(kw)))
                     ///TODO: Add category search
                     //|| ad.Categories.Contains(kw)))
                     select ad);

            //Order the query by list
            //Delimit the query to take only a page of results and append the Authors to the ads
            var pagedQuery = query.OrderByDescending(a => a.DatePosted)
                             .Skip(skip)
                             .Take(amount)
                             .Include(a => a.Author)
                             .Include(a => a.ReservedBy)
                             .Include(a => a.Price)
                             .ToList();

            return(pagedQuery);
        }
예제 #7
0
        /// <summary>
        /// Find a location from its name and delete it.
        /// </summary>
        public void DeleteLocation(string name)
        {
            var db       = DbContextControl.GetNew();
            var toDelete = new Location {
                Name = name
            };

            db.Locations.Attach(toDelete);
            db.Locations.Remove(toDelete);
            db.SaveChanges();
        }
예제 #8
0
        /// <summary>
        /// Reserves an ad
        /// </summary>
        /// <param name="id">Id of ad</param>
        /// <param name="userEmail">Email of the reserving user</param>
        /// <exception cref="PostNotFoundException"></exception>
        /// <exception cref="UserNotFoundException"></exception>
        /// <exception cref="ArgumentException">Users can not reserve their own Ad.</exception>
        /// <exception cref="AlreadyReservedException"></exception>
        /// <exception cref="NotEnoughReservationsException"></exception>
        public void ReserveAd(string id, string userEmail)
        {
            Ad   ad   = GetAd(id);
            User user = UserControl.GetInstance().GetUser(userEmail);
            var  db   = DbContextControl.GetNew();

            using (var reserveTransaction = db.Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
            {
                try
                {
                    if (user.Id == ad.ReservedBy?.Id)
                    {
                        throw new ArgumentException("Users can not reserve their own ads.");
                    }

                    if (ad.ReservedBy != null)
                    {
                        throw new AlreadyReservedException(String.Format(
                                                               "Ad with id '{0}' is already reserved by user with id '{1}'", ad.Id, ad.ReservedBy.Id));
                    }

                    if (user.Reservations < 1)
                    {
                        throw new NotEnoughReservationsException("This user can not reserve any more ads.");
                    }

                    //Get ad into context
                    db.Ads.Attach(ad);
                    db.Entry(ad).State = EntityState.Modified;

                    //Get user into context
                    db.Users.Attach(user);
                    db.Entry(user).State = EntityState.Modified;

                    //Modify ad, reserve
                    ad.ReservedBy = user;

                    //Modify user, remove points
                    user.Reservations -= 1;

                    db.SaveChanges();
                    reserveTransaction.Commit();
                }
                catch (Exception ex)
                {
                    reserveTransaction.Rollback();
                    throw ex;
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Gets all ads reserved by a specific user
        /// </summary>
        /// <param name="userEmail"></param>
        /// <returns></returns>
        /// <exception cref="UserNotFoundException"></exception>
        public IList <Ad> GetReservedAds(string userEmail)
        {
            User user   = UserControl.GetInstance().GetUser(userEmail);
            var  userId = user.Id;
            var  db     = DbContextControl.GetNew();

            return(db.Ads.Where(a => a.ReservedBy.Id == userId)
                   .Include("Author")
                   .Include("Location")
                   .Include("Price")
                   .Include("ReservedBy")
                   .OrderByDescending(a => a.DatePosted)
                   .ToList());
        }
예제 #10
0
        public void DeleteComment(string id, string userEmail)
        {
            var db = DbContextControl.GetNew();

            Comment toDelete = db.Comments.Attach(
                db.Comments.FirstOrDefault(c => c.Id == id));

            if (toDelete.Author.Email != userEmail)
            {
                throw new InvalidOperationException("Can not delete another person's comment.");
            }

            db.Entry(toDelete).State = EntityState.Deleted;
            db.SaveChanges();
        }
예제 #11
0
        public void DeleteUser(string id)
        {
            if (id == null)
            {
                return;
            }

            var  db       = DbContextControl.GetNew();
            User toDelete = new User {
                Id = id
            };

            db.Entry(toDelete).State = EntityState.Deleted;
            db.SaveChanges();
        }
예제 #12
0
        /// <summary>
        /// Returns all children of a location. Keeps the location in the list.
        /// </summary>
        /// <param name="location"></param>
        /// <param name="locationIsAlreadyValidated"></param>
        /// <returns></returns>
        public IList <Location> GetChildren(Location location, bool locationIsAlreadyValidated = false)
        {
            var      db      = DbContextControl.GetLastOrNew();
            Location current = location;

            if (!locationIsAlreadyValidated)
            {
                //Check if the location exists in the database
                current = GetLocation(db, location?.Name);

                if (current == null)
                {
                    throw new LocationNotFoundException();
                }
            }

            //Find all locations whose parent is our location
            IQueryable <Location> query
                = db.Locations.Include("Parent").Where(l => l.Parent != null && l.Parent.Name == location.Name);

            int results = query.Count();
            IList <Location> validLocations = query.ToList();
            IList <string>   children       = validLocations.ToNameList(); //Children to check, per iteration
            //We need to loop this for the children of children, until we get no more new results
            bool iterate = true;

            while (iterate) //Do while there are still objects available
            {
                //Perform query to find all Locations whose parent is one of the previous children
                query = db.Locations.Include("Parent").Where(l => l.Parent != null && children.Contains(l.Parent.Name));
                //Count
                results = query.Count();
                if (results > 0)                                              //Prepare next iteration
                {
                    var newList = query.ToList();                             //Turn the query into list of objects
                    validLocations = validLocations.Concat(newList).ToList(); //Add the newfound locations to the total list
                    children       = newList.ToNameList();                    //Specify the children to check for in the next iteration
                }
                else
                {
                    iterate = false;
                }
            }
            validLocations.Add(location);//Keep the current location in the list to simplify later use
            return(validLocations);
        }
예제 #13
0
        /// <summary>
        /// Checks if a location is within another location.
        /// An example: Aalborg is within Nordjylland, is within Denmark
        /// LocationIsWithin("Aalborg","Denmark") ---> true
        /// </summary>
        /// <param name="name">Location in question</param>
        /// <param name="parent">The larger location</param>
        /// <returns></returns>
        public bool IsWithin(string name, string parent)
        {
            //Get a reference to a Database Context from Entity Framework
            var db = DbContextControl.GetLastOrNew();

            //Make sure that the name and parent arguments are existing locations
            Location current        = GetLocation(db, name);
            Location parentLocation = GetLocation(db, parent);

            if (current == null)
            {
                throw new LocationNotFoundException("Checking if non-existing location is within another.");
            }
            if (parentLocation == null)
            {
                throw new LocationNotFoundException("Checking if a location is within a non-existing one.");
            }

            //Now we try to traverse the Location tree, to find if two locations are connected
            bool found = false; //Boolean flag to help us later

            //While the current location is not null and we haven't found a match
            while (current != null && !found)
            {
                //Check if the current location or its parent is the one parent we are looking for
                if (current.Name == parent || current.Parent?.Name == parent)
                {
                    found = true;//This makes the end result true, and also terminates the condition of the loop
                }
                //If there are no more parents, we are at the top of the tree and we are done searching
                if (current.Parent == null)
                {
                    //This terminates the condition of the loop
                    current = null;
                }
                else
                {
                    //Otherwise, switch to the parent of the current location and repeat the loop
                    current = GetLocation(db, current.Parent.Name);
                }
            }
            //If nothing is found, this remains false
            return(found);
        }
예제 #14
0
        /// <summary>
        /// Returns an ordered-by-date list of all comments that are replies to a given post.
        /// It is not within this method's responsibility to check if the post exists.
        /// </summary>
        /// <param name="replyId">The id of the specified post</param>
        /// <param name="skip">How many comments to skip from the list</param>
        /// <param name="amount">How many comments to fetch.</param>
        /// <returns></returns>
        public IList <Comment> GetReplies(string replyId, int skip, int amount)
        {
            if (amount > 64)
            {
                amount = 64; //throttling the amount to spare the db server
            }
            var db = DbContextControl.GetNew();

            IQueryable <Comment> query = db.Comments;

            var pagedQuery = query.Where(c => c.ReplyId == replyId)
                             .OrderByDescending(c => c.DatePosted)
                             .Skip(skip)
                             .Take(amount)
                             .Include(c => c.Author)
                             .ToList();

            return(pagedQuery);
        }
예제 #15
0
        /// <summary>
        /// Posts an Ad, persists to the database
        /// </summary>
        /// <param name="authorEmail"></param>
        /// <param name="title"></param>
        /// <param name="content"></param>
        /// <param name="locationName"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public Ad PostAd(string authorEmail, string title, string content, string locationName = null, AdType type = AdType.Other)
        {
            var db = DbContextControl.GetNew();

            Ad ad = new Ad
            {
                Content    = content,
                DatePosted = DateTime.Now,
                LastEdited = DateTime.Now,
                ExpDate    = DateTime.Now,
                Views      = 0,
                Title      = title,
                Location   = null,
                Price      = null,
                Type       = type,
            };

            //Find a user and attach him to the DB context
            var authorFull = db.Users.Attach(
                db.Users.FirstOrDefault(u => u.Email == authorEmail));

            //Attach the user to the Ad
            ad.Author = authorFull;

            //Find a location and attach it to the DB context and to the Ad
            if (locationName != null)
            {
                var locationFull = db.Locations.Attach(new Location {
                    Name = locationName
                });
                ad.Location = locationFull;
            }

            ad.Price = new Price {
                Id = ad.Id, Type = PriceType.Free, High = 0, Low = 0
            };

            db.Ads.Add(ad);
            db.SaveChanges();

            return(ad);
        }
예제 #16
0
        /// <summary>
        /// Updates an ad. Requires author email.
        /// </summary>
        /// <param name="authorEmail"></param>
        /// <param name="id"></param>
        /// <param name="title"></param>
        /// <param name="content"></param>
        /// <param name="locationName"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public Ad UpdateAd(string authorEmail, string id, string title, string content, string locationName = null, AdType type = AdType.Other)
        {
            using (var db = DbContextControl.GetNew())
            {
                Ad  ad    = db.Ads.FirstOrDefault(a => a.Id == id);
                var entry = db.Entry(ad);

                if (ad.Author.Email != authorEmail)
                {
                    throw new InvalidOperationException("Can not edit another person's ad!");
                }

                if (title != null && title != ad.Title)
                {
                    ad.Title = title;
                    entry.Property("Title").IsModified = true;
                }

                //Find a location and attach it to the DB context and to the Ad
                if (locationName != null && locationName != ad.Location.Name)
                {
                    var locationFull = db.Locations.Attach(new Location {
                        Name = locationName
                    });
                    //ad.Location = locationFull;
                    entry.Reference("Location").CurrentValue = locationFull;
                }

                if (content != null && content != ad.Content)
                {
                    ad.Content = content;
                    entry.Property("Content").IsModified = true;
                }

                ad.LastEdited = DateTime.Now;
                entry.Property("LastEdited").IsModified = true;

                db.SaveChanges();

                return(ad);
            }
        }
예제 #17
0
        /// <summary>
        /// This is an administrative method, not available to users.
        /// </summary>
        public void RegisterLocation(string name, LocationType type, string parentName = null)
        {
            var db = DbContextControl.GetNew();

            Location parent = null;

            if (parentName != null)
            {
                parent = AttachLocation(db, parentName);
            }

            Location location = new Location
            {
                Name   = name,
                Type   = type,
                Parent = parent,
            };

            db.Locations.Add(location);
            db.SaveChanges();
        }
예제 #18
0
        /// <summary>
        /// Fetches from all ads. Ordered by date. This method is used on the home page.
        /// </summary>
        public IList <Ad> GetAds(int skip, int amount)
        {
            if (amount > Throttle)
            {
                amount = Throttle;
            }

            var db = DbContextControl.GetNew();

            IQueryable <Ad> query = db.Ads;

            var pagedQuery = query
                             .OrderByDescending(a => a.DatePosted)
                             .Skip(skip)
                             .Take(amount)
                             .Include(a => a.Author)
                             .Include(a => a.Location)
                             .Include(a => a.ReservedBy)
                             .ToList();

            return(pagedQuery);
        }
예제 #19
0
        private void SeedAds()
        {
            //TODO: Refactor
            var db = DbContextControl.GetNew();

            if (db.Ads.Count() == 0)
            {
                if (db.Users.Count() == 0)
                {
                    MigrationSeed.SeedUsers();
                }
                MigrationSeed.SeedAds();

                foreach (var ad in MigrationSeed.Ads)
                {
                    PostAd(ad.Author.Email, ad.Title, ad.Content, ad.Location.Name, ad.Type);
                }

                var blueCar = MigrationSeed.Ads.FirstOrDefault(a => a.Title == "Selling blue sports car");
                ReserveAd(blueCar?.Id, "*****@*****.**");
                CommentControl.GetInstance().PostComment(blueCar.Id, "Interested!", "*****@*****.**");
            }
        }
예제 #20
0
        /// <summary>
        /// Gets a page of ads that are within a location.
        /// </summary>
        /// <returns></returns>
        public IList <Ad> GetAdsWithinLocation(int skip, int amount, string location)
        {
            if (amount > Throttle)
            {
                amount = Throttle;
            }

            IList <string> possibleLocationNames = GetPossibleLocationNames(location);

            ServiceDbContext db = DbContextControl.GetLastOrNew();

            IQueryable <Ad> query = db.Ads.Include("Location")
                                    .Where(a => a.Location != null &&
                                           possibleLocationNames.Contains(a.Location.Name));

            var pagedQuery = query
                             .OrderByDescending(a => a.DatePosted)
                             .Skip(skip)
                             .Take(amount)
                             .Include(a => a.Author)
                             .ToList();

            return(pagedQuery);
        }
예제 #21
0
        /// <summary>
        /// Get a list of all locations that contain this location.
        /// Starts with the current location.
        /// Ordered from smallest to largest containing location.
        /// </summary>
        /// <param name="location">The location whose parents you are looking for.</param>
        /// <returns></returns>
        public IList <Location> GetParents(Location location, bool locationIsAlreadyValidated = false)
        {
            var      db      = DbContextControl.GetLastOrNew();
            Location current = location;

            if (!locationIsAlreadyValidated)
            {
                //Check if the location exists in the database
                current = GetLocation(db, location?.Name);

                if (current == null)
                {
                    throw new LocationNotFoundException();
                }
            }

            IList <Location> locations = new List <Location>();

            //While we aren't at a null location
            while (current != null)
            {
                //Add the current location to our list
                locations.Add(current);
                //Get the parent of the current (null if at the top of the tree)
                if (current.Parent == null)
                {
                    current = null; //If no more parents, terminate the loop
                }
                else
                {
                    current = GetLocation(current.Parent.Name);
                }
            }

            return(locations);
        }
예제 #22
0
        /// <summary>
        /// Find a location from its name, since it's the only possible key.
        /// This queries the DB.
        /// </summary>
        /// <param name="name"></param>
        public Location GetLocation(string name)
        {
            var db = DbContextControl.GetLastOrNew();

            return(db.Locations.Include("Parent").FirstOrDefault(l => l.Name.ToLower() == name.ToLower()));
        }