public HttpResponseMessage RegisterUser([FromBody]UserRegisterModel user)
        {
            HttpResponseMessage responseMessage = this.PerformOperation(() =>
                {
                    UserValidator.ValidateAuthenticationCode(user.AuthCode);
                    UserValidator.ValidateNickname(user.Nickname);
                    UserValidator.ValidateUsername(user.Username);

                    var context = new TelerikAcademyForumContext();
                    using (context)
                    {
                        User exstingUserEntity = context.Users.FirstOrDefault<User>(
                            u => u.Username == user.Username.ToLower() || u.Nickname.ToLower() == user.Nickname.ToLower());
                        if (exstingUserEntity != null)
                        {
                            throw new InvalidOperationException("User already exists!");
                        }

                        User newUserEntity = UsersMapper.ToEntity(user);
                        context.Users.Add(newUserEntity);
                        context.SaveChanges();

                        newUserEntity.SessionKey = UserValidator.GenerateSessionKey(newUserEntity.ID);
                        context.SaveChanges();

                        UserLoggedModel loggedUser = UsersMapper.ToUserLoggedModel(newUserEntity);
                        return this.Request.CreateResponse(HttpStatusCode.Created, loggedUser);
                    }
                });

            return responseMessage;
        }
        public HttpResponseMessage LoginUser([FromBody]UserLoginModel user)
        {
            HttpResponseMessage responseMessage = this.PerformOperation(() =>
            {
                UserValidator.ValidateAuthenticationCode(user.AuthCode);
                UserValidator.ValidateUsername(user.Username);

                var context = new TelerikAcademyForumContext();
                using (context)
                {
                    var userEntity = context.Users.FirstOrDefault(
                        u => u.AuthCode == user.AuthCode && u.Username == user.Username.ToLower());
                    if (userEntity == null)
                    {
                        throw new InvalidOperationException("User not registered!");
                    }

                    userEntity.SessionKey = UserValidator.GenerateSessionKey(userEntity.ID);
                    context.SaveChanges();

                    UserLoggedModel loggedUser = UsersMapper.ToUserLoggedModel(userEntity);
                    return this.Request.CreateResponse(HttpStatusCode.OK, loggedUser);
                }
            });

            return responseMessage;
        }
        public IQueryable<PostModel> GetAll(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string sessionKey)
        {
            var allPostModels = this.PerformOperation(() =>
            {
                UserValidator.ValidateSessionKey(sessionKey);

                var context = new TelerikAcademyForumContext();
                using (context)
                {
                    var postModels = new List<PostModel>();
                    var postEntities = context.Posts
                        .Include("Author").Include("Thread").Include("Votes").Include("Comments")
                        .OrderByDescending(p => p.PostDate);
                    foreach (var postEntity in postEntities)
                    {
                        postModels.Add(PostsMapper.ToModel(postEntity));
                    }

                    return postModels.AsQueryable<PostModel>();
                }
            });

            return allPostModels;
        }
        public static Category CreateOrLoadCategory(string category, TelerikAcademyForumContext context)
        {
            string categoryLowerCase = category.ToLower().Trim();
            Category existingCategory = context.Categories
                .FirstOrDefault<Category>(c => c.Name.ToLower() == categoryLowerCase);
            if (existingCategory != null)
            {
                return existingCategory;
            }

            Category newCategory = new Category() { Name = category };
            context.Categories.Add(newCategory);
            context.SaveChanges();

            return newCategory;
        }
        public IQueryable<string> GetAll(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string sessionKey)
        {
            var categoryModels = this.PerformOperation(() =>
            {
                UserValidator.ValidateSessionKey(sessionKey);

                var context = new TelerikAcademyForumContext();
                var categories =
                        from category in context.Categories
                        select category.Name;

                return categories;
            });

            return categoryModels;
        }
        public static Thread ToEntity(
            ThreadModel threadModel,
            string sessionKey,
            TelerikAcademyForumContext context)
        {
            Thread threadEntity = new Thread()
            {
                Title = threadModel.Title,
                Content = threadModel.Content,
                DateCreated = DateTime.Now,
                Author = context.Users.FirstOrDefault<User>(u => u.SessionKey == sessionKey)
            };

            foreach (var category in threadModel.Categories)
            {
                threadEntity.Categories.Add(Extensions.CreateOrLoadCategory(category, context));
            }

            return threadEntity;
        }
        public HttpResponseMessage Add([FromBody]ThreadModel thread,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string sessionKey)
        {
            HttpResponseMessage httpResponse = this.PerformOperation(() =>
            {
                UserValidator.ValidateSessionKey(sessionKey);

                var context = new TelerikAcademyForumContext();
                using (context)
                {
                    var newThreadEntity = ThreadsMapper.ToEntity(thread, sessionKey, context);
                    context.Threads.Add(newThreadEntity);
                    context.SaveChanges();

                    thread.ID = newThreadEntity.ID;
                }

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

            return httpResponse;
        }
        public HttpResponseMessage VotePost(int postID, [FromBody]int vote,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string sessionKey)
        {
            var httpResponse = this.PerformOperation(() =>
            {
                UserValidator.ValidateSessionKey(sessionKey);

                if (vote < 0 || vote > 5)
                {
                    throw new ArgumentOutOfRangeException("vote", "Vote cannot be less than 0 and more than 5!");
                }

                var context = new TelerikAcademyForumContext();
                using (context)
                {
                    var post = context.Posts.Find(postID);
                    if (post == null)
                    {
                        var httpErrorResponse = this.Request.CreateErrorResponse(
                            HttpStatusCode.NotFound, "Post with provided ID not found!");
                        throw new HttpResponseException(httpErrorResponse);
                    }

                    post.Votes.Add(new Vote()
                        {
                            User = context.Users.FirstOrDefault<User>(u => u.SessionKey == sessionKey),
                            Value = vote
                        });

                    context.SaveChanges();
                }

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

            return httpResponse;
        }
        public IQueryable<ThreadModel> GetAll(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string sessionKey)
        {
            IQueryable<ThreadModel> allThreadModels = this.PerformOperation(() =>
            {
                UserValidator.ValidateSessionKey(sessionKey);

                var threadModels = new List<ThreadModel>();
                using (var context = new TelerikAcademyForumContext())
                {
                    var threadEntities = context.Threads
                        .Include("Categories").Include("Posts").Include("Author")
                        .OrderByDescending(thr => thr.DateCreated);
                    foreach (var threadEntity in threadEntities.ToList())
                    {
                        threadModels.Add(ThreadsMapper.ToModel(threadEntity));
                    }
                }

                return threadModels.AsQueryable<ThreadModel>();
            });

            return allThreadModels;
        }
        public HttpResponseMessage LogoutUser(
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string sessionKey)
        {
            HttpResponseMessage responseMessage = this.PerformOperation(() =>
            {
                UserValidator.ValidateSessionKey(sessionKey);

                var context = new TelerikAcademyForumContext();
                using (context)
                {
                    var loggedUserEntity = context.Users.FirstOrDefault<User>(u => u.SessionKey == sessionKey);
                    if (loggedUserEntity == null)
                    {
                        throw new InvalidOperationException("Invalid user!");
                    }

                    loggedUserEntity.SessionKey = null;
                    context.SaveChanges();
                }

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

            return responseMessage;
        }
        public HttpResponseMessage CommentPost(int postID, [FromBody]string comment,
            [ValueProvider(typeof(HeaderValueProviderFactory<string>))]string sessionKey)
        {
            var httpResponse = this.PerformOperation(() =>
            {
                UserValidator.ValidateSessionKey(sessionKey);

                if (comment == null)
                {
                    throw new ArgumentNullException("comment", "Comment cannot be null!");
                }

                var context = new TelerikAcademyForumContext();
                using (context)
                {
                    var post = context.Posts.Find(postID);
                    if (post == null)
                    {
                        var httpErrorResponse = this.Request.CreateErrorResponse(
                            HttpStatusCode.NotFound, "Post with provided ID not found!");
                        throw new HttpResponseException(httpErrorResponse);
                    }

                    post.Comments.Add(new Comment()
                    {
                        Author = context.Users.FirstOrDefault<User>(u => u.SessionKey == sessionKey),
                        CommentDate = DateTime.Now,
                        Content = comment
                    });

                    context.SaveChanges();
                }

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

            return httpResponse;
        }