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(); }
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); }
/// <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(); }
public void DeleteReplies(string replyId) { var db = DbContextControl.GetNew(); var comments = db.Comments.Where(c => c.ReplyId == replyId); db.Comments.RemoveRange(comments); db.SaveChanges(); }
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(); }
/// <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); }
/// <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(); }
/// <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; } } }
/// <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()); }
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(); }
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(); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); } }
/// <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(); }
/// <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); }
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!", "*****@*****.**"); } }
/// <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); }
/// <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); }
/// <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())); }