public HttpResponseMessage AddImage(
            int placeId,
            ImageModel imageModel,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        var user = UsersController.GetUserBySessionKey(context, sessionKey);
                        var place = GetAllPlaces(context).FirstOrDefault(p => p.Id == placeId);
                        place.Images.Add(new Image()
                        {
                            Url = imageModel.ImageUrl,
                            Place = place,
                            User = user
                        });
                        context.SaveChanges();

                        return this.Request.CreateResponse(HttpStatusCode.NoContent);
                    }
                });

            return responseMsg;
        }
        public HttpResponseMessage AddComment(
            int placeId,
            CommentModel commentModel,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        var user = UsersController.GetUserBySessionKey(context, sessionKey);
                        var place = context.Places.FirstOrDefault(p => p.Id == placeId);
                        if (place == null)
                        {
                            throw new ArgumentNullException("place", "A place with the specified ID does not exist.");
                        }

                        place.Comments.Add(new Comment()
                        {
                            Content = commentModel.Content,
                            Date = DateTime.Now,
                            Place = place,
                            User = user,
                        });
                        context.SaveChanges();

                        return this.Request.CreateResponse(HttpStatusCode.OK, commentModel);
                    }
                });

            return responseMsg;
        }
        protected void Application_Start()
        {
            Database.SetInitializer<PlacesContext>(new MigrateDatabaseToLatestVersion<PlacesContext, Configuration>());
            using (var context = new PlacesContext())
            {
                context.Users.ToList();
            }

            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
        // GET api/countries
        public HttpResponseMessage GetCountries([ValueProvider(typeof(HeaderValueProviderFactory<string>))]
                                                string sessionKey)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    UsersController.GetUserBySessionKey(context, sessionKey);
                    var countriesModel = context.Countries
                                                .Select(c => new CountrySmallModel()
                                                       {
                                                           Id = c.Id,
                                                           Name = c.Name
                                                       });

                    return this.Request.CreateResponse(HttpStatusCode.OK, countriesModel);
                });

            return responseMessage;
        }
        public HttpResponseMessage CreateComment(CommentModel commentModel, int id,
           [ValueProvider(typeof(HeaderValueProviderFactory<string>))] string sessionKey)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    using (context)
                    {
                        var user = UsersController.GetUserBySessionKey(context, sessionKey);
                        var place = context.Places.FirstOrDefault(p => p.Id == id);

                        if (user == null)
                        {
                            throw new InvalidOperationException("Invalid username or password!");
                        }

                        var comment = new Comment()
                        {
                            Content = commentModel.Content,
                            Date = DateTime.Now,
                            User = user
                        };

                        place.Comments.Add(comment);
                        context.SaveChanges();

                        var createdComment = new CommentModel()
                        {
                            Date = comment.Date,
                            Content = comment.Content,
                            PostedBy = comment.User.Nickname
                        };

                        var response = this.Request.CreateResponse(HttpStatusCode.Created, createdComment);
                        return response;
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage GetTownById(int townId, [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
                                              string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    var context = new PlacesContext();

                    using (context)
                    {
                        var townEntities = context.Towns;
                        var townEntity = townEntities.Where(t => t.Id == townId).FirstOrDefault();

                        var townModel = new TownModelFull();
                        townModel.Id = townEntity.Id;
                        townModel.Name = townEntity.Name;
                        townModel.Country = new CountrySmallModel()
                        {
                            Id = townEntity.Country.Id,
                            Name = townEntity.Country.Name
                        };
                        townModel.Places =
                            from placeEntity in townEntity.Places
                            select new PlaceModelSmall()
                            {
                                Id = placeEntity.Id,
                                Name = placeEntity.Name,
                                Content = placeEntity.Content
                            };

                        return this.Request.CreateResponse(HttpStatusCode.OK, townModel);
                    }
                }
            );

            return responseMsg;
        }
        public IEnumerable<UserEditModel> GetAllUsers([ValueProvider(typeof(HeaderValueProviderFactory<string>))] string sessionKey)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    // check if user is valid
                    User existingUser = GetUserBySessionKey(context, sessionKey);
                    if (existingUser == null)
                    {
                        throw new ArgumentNullException("The user does not exist or is already logged out.");
                    }

                    // check if user is admin
                    if (existingUser.Role != Role.Admin)
                    {
                        throw new InvalidOperationException("User is not admin and cannot see admin information.");
                    }

                    var userEntities = context.Users;

                    var userModels =
                                    from userEntity in userEntities
                                    select new UserEditModel()
                                    {
                                        Id = userEntity.Id,
                                        Nickname = userEntity.Nickname,
                                        Role = (int)userEntity.Role
                                    };

                    return userModels.ToList();

                });

            return responseMessage;
        }
        // GET api/countries/{id}
        public HttpResponseMessage GetCountry(
            int id,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    var context = new PlacesContext();
                    using (context)
                    {
                        UsersController.GetUserBySessionKey(context, sessionKey);
                        Country country = context.Countries.Find(id);
                        if (country == null)
                        {
                            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
                        }

                        var countryModel = new CountryFullModel()
                        {
                            Towns = country.Towns.Select(
                                c => new TownModel()
                                {
                                    CountryId = c.Country.Id,
                                    Id = c.Id,
                                    Name = c.Name
                                }),
                            Id = country.Id,
                            Name = country.Name
                        };

                        return this.Request.CreateResponse(HttpStatusCode.OK, countryModel);
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage GetPlaceById(
            int placeId,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        UsersController.GetUserBySessionKey(context, sessionKey);
                        var place = GetAllPlaces(context).FirstOrDefault(p => p.Id == placeId);
                        if (place == null)
                        {
                            throw new ArgumentNullException("place", "A place with the specified ID does not exist.");
                        }
                        var model = new PlaceGetModel()
                        {
                            Id = place.Id,
                            Name = place.Name,
                            Town = new TownModel()
                            {
                                Id = place.Town.Id,
                                Name = place.Town.Name,
                                CountryId = place.Town.Country.Id
                            },
                            Country = new CountrySmallModel()
                            {
                                Id = place.Town.Country.Id,
                                Name = place.Town.Country.Name
                            },
                            Content = place.Content,
                            ImageUrls = place.Images.Select(i => i.Url),
                            Comments = (from comment in place.Comments
                                        select new CommentModel()
                                        {
                                            Content = comment.Content,
                                            Date = comment.Date,
                                            PostedBy = comment.User.Nickname
                                        }).OrderByDescending(c => c.Date)
                        };

                        return this.Request.CreateResponse(HttpStatusCode.OK, model);
                    }
                });

            return responseMsg;
        }
        public HttpResponseMessage PostTown(TownModel model, [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
                                               string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    var context = new PlacesContext();

                    using (context)
                    {
                        Town townEntity = new Town();
                        CountrySmallModel countryModel = new CountrySmallModel();
                        var countryEntity = context.Countries.Where(c => c.Id == model.CountryId).FirstOrDefault();

                        if (countryEntity != null)
                        {
                            countryModel.Id = countryEntity.Id;
                            countryModel.Name = countryEntity.Name;
                            townEntity.Country = countryEntity;
                        }
                        else
                        {
                            throw new ArgumentException("No town with this id was found");
                        }

                        townEntity.Name = model.Name;
                        context.Towns.Add(townEntity);
                        context.SaveChanges();

                        // get the id from the entity added in the db
                        model.Id = townEntity.Id;

                        return this.Request.CreateResponse(HttpStatusCode.Created, model);
                    }
                }
            );

            return responseMsg;
        }
        public HttpResponseMessage LoginUser(UserRegisteredModel userModel)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    using (context)
                    {
                        this.ValidateUsername(userModel.Username);
                        this.ValidateAuthCode(userModel.AuthCode);

                        string usernameToLower = userModel.Username.ToLower();

                        User existingUser = context.Users
                                                   .FirstOrDefault(u => u.Username.ToLower() == usernameToLower);
                        if (existingUser == null)
                        {
                            throw new ArgumentNullException("The user does not exist.");
                        }

                        if (existingUser.SessionKey == null)
                        {
                            existingUser.SessionKey = this.GenerateSessionKey(existingUser.Id);
                            context.SaveChanges();
                        }

                        UserLoggedInModel loggedUser = new UserLoggedInModel()
                        {
                            Nickname = existingUser.Nickname,
                            SessionKey = existingUser.SessionKey
                        };

                        return this.Request.CreateResponse(HttpStatusCode.Created, loggedUser);
                    }
                });

            return responseMessage;
        }
        internal static User GetUserBySessionKey(PlacesContext context, string sessionKey)
        {
            var user = context.Users.FirstOrDefault(u => u.SessionKey == sessionKey);
            if (user == null)
            {
                throw new ArgumentNullException("user", "The user does not exist or is already logged out.");
            }

            return user;
        }
        public HttpResponseMessage RegisterUser(UserRegisteredModel userModel)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    using (context)
                    {
                        this.ValidateUsername(userModel.Username);
                        this.ValidateNickname(userModel.Nickname);
                        this.ValidateAuthCode(userModel.AuthCode);

                        string usernameToLower = userModel.Username.ToLower();
                        string nicknameToLower = userModel.Nickname.ToLower();

                        User user = context.Users
                                           .FirstOrDefault(u => u.Username.ToLower() == usernameToLower ||
                                                                u.Nickname == nicknameToLower);
                        if (user != null)
                        {
                            throw new InvalidOperationException("The user already exists.");
                        }

                        user = new User()
                        {
                            Username = usernameToLower,
                            Nickname = userModel.Nickname,
                            AuthCode = userModel.AuthCode,
                            Role = Role.User
                        };
                        context.Users.Add(user);
                        context.SaveChanges();

                        user.SessionKey = this.GenerateSessionKey(user.Id);
                        context.SaveChanges();

                        UserLoggedInModel loggedInUser = new UserLoggedInModel()
                        {
                            Nickname = user.Nickname,
                            SessionKey = user.SessionKey
                        };

                        return this.Request.CreateResponse(HttpStatusCode.Created, loggedInUser);
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage PutUser([FromBody] UserEditModel userEditModel, [FromUri]int id, [ValueProvider(typeof(HeaderValueProviderFactory<string>))] string sessionKey)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        User existingUser = GetUserBySessionKey(context, sessionKey);

                        if (existingUser == null)
                        {
                            throw new ArgumentNullException("The user does not exist or is already logged out.");
                        }

                        // check if user is admin
                        if (existingUser.Role != Role.Admin)
                        {
                            throw new InvalidOperationException("User is not admin and cannot see admin information.");
                        }

                        User editedUser = context.Users.Find(userEditModel.Id);

                        if (editedUser == null)
                        {
                            throw new ArgumentNullException(String.Format("Invalid user id: {0}. User not found.", userEditModel.Id));
                        }

                        if (ModelState.IsValid && id == userEditModel.Id)
                        {
                            editedUser.Nickname = userEditModel.Nickname;
                            editedUser.Role = (Role)userEditModel.Role;

                            context.Entry(editedUser).State = EntityState.Modified;

                            try
                            {
                                context.SaveChanges();
                            }
                            catch (DbUpdateConcurrencyException)
                            {
                                return Request.CreateResponse(HttpStatusCode.NotFound);
                            }

                            return Request.CreateResponse(HttpStatusCode.NoContent);
                        }
                        else
                        {
                            return Request.CreateResponse(HttpStatusCode.BadRequest);
                        }
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage LogoutUser(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMessage = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    using (context)
                    {
                        User existingUser = context.Users
                                                   .FirstOrDefault(u => u.SessionKey == sessionKey);
                        if (existingUser == null)
                        {
                            throw new ArgumentNullException("The user does not exist or is already logged out.");
                        }

                        existingUser.SessionKey = null;
                        context.SaveChanges();

                        return this.Request.CreateResponse(HttpStatusCode.NoContent);
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage PostPlace(
            PlaceModel placeModel,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        var user = UsersController.GetUserBySessionKey(context, sessionKey);
                        if (user.Role != Role.Admin)
                        {
                            throw new InvalidOperationException("User is not admin and cannot see admin information.");
                        }

                        var place = new Place();
                        place.Name = placeModel.Name;
                        place.User = user;
                        if (placeModel.TownId != 0)
                        {
                            var contextTown = context.Towns.Find(placeModel.TownId);
                            if (contextTown != null)
                            {
                                place.Town = contextTown;
                            }
                            else
                            {
                                throw new ArgumentNullException("town", "The town does not exist.");
                            }
                        }

                        place.Content = placeModel.Content;
                        if (placeModel.ImageUrls != null)
                        {
                            foreach (var imageUrl in placeModel.ImageUrls)
                            {
                                place.Images.Add(new Image()
                                {
                                    Place = place,
                                    Url = imageUrl,
                                    User = user
                                });
                            }
                        }

                        context.Places.Add(place);
                        context.SaveChanges();
                        placeModel.Id = place.Id;
                    }
                    return this.Request.CreateResponse(HttpStatusCode.Created, placeModel);
                });

            return responseMsg;
        }
        // POST api/Country
        public HttpResponseMessage PostCountry(
            CountrySmallModel countryModel,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMessage = PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();
                    var country = new Country()
                    {
                        Name = countryModel.Name,
                        Id = countryModel.Id
                    };

                    if (!context.Countries.Any(c => c.Name.ToLower() == countryModel.Name.ToLower()))
                    {
                        context.Countries.Add(country);
                        context.SaveChanges();
                    }

                    countryModel.Id = country.Id;
                    return this.Request.CreateResponse(HttpStatusCode.Created, countryModel);
                });

            return responseMessage;
        }
 private IQueryable<Place> GetAllPlaces(PlacesContext context)
 {
     return context.Places
         .Include(p => p.Town)
         .Include(p => p.Town.Country)
         .Include(p => p.Images)
         .Include(p => p.Comments)
         .Include(p => p.Comments
             .Select(c => c.User));
 }
        public HttpResponseMessage GetAllPlaces(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]
            string sessionKey)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(
                () =>
                {
                    PlacesContext context = new PlacesContext();

                    using (context)
                    {
                        UsersController.GetUserBySessionKey(context, sessionKey);
                        var placeModels = new HashSet<PlaceGetModel>();
                        foreach (var place in GetAllPlaces(context))
                        {
                            var model = new PlaceGetModel()
                            {
                                Id = place.Id,
                                Name = place.Name,
                                Town = new TownModel()
                                {
                                    Id = place.Town.Id,
                                    Name = place.Town.Name,
                                    CountryId = place.Town.Country.Id
                                },
                                Country = new CountrySmallModel()
                                {
                                    Id = place.Town.Country.Id,
                                    Name = place.Town.Country.Name
                                },
                                Content = place.Content,
                                ImageUrls = place.Images.Select(i => i.Url),
                                Comments = (from comment in place.Comments
                                            select new CommentModel()
                                            {
                                                Content = comment.Content,
                                                Date = comment.Date,
                                                PostedBy = comment.User.Nickname
                                            })
                            };
                            placeModels.Add(model);
                        }

                        return this.Request.CreateResponse(HttpStatusCode.OK, placeModels);
                    }
                });

            return responseMsg;
        }