Пример #1
0
        public BanUserFromSubResponse Handle(BanUserFromSub command)
        {
            var response = new BanUserFromSubResponse();

            try
            {
                var user = command.UserId.HasValue ? _membershipService.GetUserById(command.UserId.Value) : _membershipService.GetUserByUserName(command.UserName);

                if (user == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                var bannedBy = _membershipService.GetUserById(command.BannedBy);

                if (bannedBy == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                var sub = command.SubId.HasValue
                    ? _subService.GetSubById(command.SubId.Value)
                    : _subService.GetSubByName(command.SubName);

                if (sub == null)
                {
                    response.Error = "Invalid sub.";
                    return(response);
                }

                if (!_permissionDao.CanUserManageSubAccess(bannedBy, sub.Id))
                {
                    response.Error = "You are not authorized to ban.";
                    return(response);
                }

                _subUserBanService.BanUserFromSub(sub.Id, user.Id, user.UserName, command.DateBanned, command.BannedBy, command.ReasonPrivate, command.ReasonPublic);

                return(response);
            }
            catch (Exception ex)
            {
                // TODO: log error
                response.Error = "An unknown error occured.";
                return(response);
            }
        }
Пример #2
0
        public BanUserFromSubResponse Handle(BanUserFromSub command)
        {
            var response = new BanUserFromSubResponse();

            try
            {
                var user = command.UserId.HasValue ? _membershipService.GetUserById(command.UserId.Value) : _membershipService.GetUserByUserName(command.Username);

                if (user == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                var bannedBy = _membershipService.GetUserById(command.BannedBy);

                if (bannedBy == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                var sub = command.SubId.HasValue
                    ? _subService.GetSubById(command.SubId.Value)
                    : _subService.GetSubByName(command.SubName);

                if (sub == null)
                {
                    response.Error = "Invalid sub.";
                    return(response);
                }

                if (!_permissionService.CanUserManageSubAccess(bannedBy, sub.Id))
                {
                    response.Error = "You are not authorized to ban.";
                    return(response);
                }

                _subUserBanService.BanUserFromSub(sub.Id, user.Id, command.DateBanned, command.BannedBy, command.Reason, command.Expires);
            }
            catch (Exception ex)
            {
                // todo: log
                response.Error = ex.Message;
            }

            return(response);
        }
Пример #3
0
        public EditSubResponse Handle(EditSub command)
        {
            var response = new EditSubResponse();

            try
            {
                var sub = _subService.GetSubByName(command.Name);

                if (sub == null)
                {
                    response.Error = "No sub found with the given name.";
                    return(response);
                }

                var user = _membershipService.GetUserById(command.EditedByUserId);

                if (user == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                if (!_subService.CanUserEditSub(user.UserName, sub.Name))
                {
                    response.Error = "You are not allowed to modify this sub.";
                    return(response);
                }

                if (string.IsNullOrEmpty(command.Description))
                {
                    response.Error = "Please describe your sub.";
                    return(response);
                }

                sub.Description = command.Description;
                sub.SidebarText = command.SidebarText;

                _subService.UpdateSub(sub);
            }
            catch (Exception ex)
            {
                // todo: log
                response.Error = ex.Message;
            }

            return(response);
        }
Пример #4
0
        public EditSubStylesCommandResponse Handle(EditSubStylesCommand command)
        {
            var response = new EditSubStylesCommandResponse();

            try
            {
                var user = _membershipService.GetUserById(command.EditedByUserId);
                if (user == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                var sub = command.SubId.HasValue
                    ? _subService.GetSubById(command.SubId.Value)
                    : _subService.GetSubByName(command.SubName);
                if (sub == null)
                {
                    response.Error = "Invalid sub.";
                    return(response);
                }

                if (!_permissionService.CanUserManageSubStyles(user, sub.Id))
                {
                    response.Error = "You are not authorized to manage styles for this sub.";
                    return(response);
                }

                var styles = _subStylesService.GetStylesForSub(sub.Id);
                if (styles == null)
                {
                    styles = new SubCss();
                }

                styles.SubId                 = sub.Id;
                styles.CssType               = command.CssType;
                styles.Embedded              = command.Embedded;
                styles.ExternalCss           = command.ExternalCss;
                styles.GitHubCssProjectName  = command.GitHubCssProjectName;
                styles.GitHubCssProjectTag   = command.GitHubCssProjectTag;
                styles.GitHubLessProjectName = command.GitHubLessProjectName;
                styles.GitHubLessProjectTag  = command.GitHubLessProjectTag;

                _subStylesService.UpdateStylesForSub(styles);
            }
            catch (Exception ex)
            {
                _logger.Error("Error trying to edit a sub's styles.", ex);
                response.Error = "An unknown error occured.";
            }

            return(response);
        }
Пример #5
0
        public RemoveModFromSubResponse Handle(RemoveModFromSub command)
        {
            var response = new RemoveModFromSubResponse();

            try
            {
                var requestingUser = _membershipService.GetUserById(command.RequestingUser);
                if (requestingUser == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                var userToRemove = command.UserIdToRemove.HasValue
                   ? _membershipService.GetUserById(command.UserIdToRemove.Value)
                   : _membershipService.GetUserByUserName(command.UserNameToRemove);
                if (userToRemove == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                Sub sub = null;

                if (command.SubId.HasValue)
                {
                    sub = _subService.GetSubById(command.SubId.Value);
                }
                else if (!string.IsNullOrEmpty(command.SubName))
                {
                    sub = _subService.GetSubByName(command.SubName);
                }

                if (sub == null)
                {
                    response.Error = "Invalid sub.";
                    return(response);
                }

                var userToRemoveModInfo = _moderationService.GetModeratorInfoForUserInSub(userToRemove.Id, sub.Id);
                if (userToRemoveModInfo == null)
                {
                    response.Error = "The user is not a mod of this sub.";
                    return(response);
                }

                if (requestingUser.IsAdmin)
                {
                    _moderationService.RemoveModFromSub(userToRemove.Id, sub.Id);
                }
                else
                {
                    var requestingUserModInfo = _moderationService.GetModeratorInfoForUserInSub(requestingUser.Id, sub.Id);
                    if (requestingUserModInfo == null)
                    {
                        response.Error = "You are not a mod of this sub.";
                        return(response);
                    }

                    if (
                        // if the user is removing himself (doable)
                        requestingUser.Id == userToRemove.Id ||
                        // or the requesting user is an admin
                        requestingUser.IsAdmin ||
                        // or the user has has "full" access and the user we are changing has is a newby.
                        (requestingUserModInfo.AddedOn <=
                         userToRemoveModInfo.AddedOn &&
                         requestingUserModInfo.Permissions.HasFlag(
                             ModeratorPermissions.All))
                        )
                    {
                        _moderationService.RemoveModFromSub(userToRemove.Id, sub.Id);
                    }
                    else
                    {
                        response.Error = "You are not permitted to remove the mod from this sub.";
                        return(response);
                    }
                }
            }
            catch (Exception ex)
            {
                response.Error = "An unknown error occured.";
                _logger.Error("An error occured removing a user from sub.", ex);
            }

            return(response);
        }
Пример #6
0
        public CreateSubResponse Handle(CreateSub command)
        {
            var response = new CreateSubResponse();

            try
            {
                if (string.IsNullOrEmpty(command.Name))
                {
                    response.Error = "Sub name is required.";
                    return(response);
                }

                if (!Regex.IsMatch(command.Name, "^[a-zA-Z0-9]*$"))
                {
                    response.Error = "No spaces or special characters.";
                    return(response);
                }

                if (command.Name.Length > 20)
                {
                    response.Error = "The name length is limited to 20 characters.";
                    return(response);
                }

                if (string.IsNullOrEmpty(command.Description))
                {
                    response.Error = "Please describe your sub.";
                    return(response);
                }

                if (!string.IsNullOrEmpty(command.SubmissionText) && command.SubmissionText.Length > 1000)
                {
                    response.Error = "The sidebar text cannot be greater than 1000 characters";
                    return(response);
                }

                if (!string.IsNullOrEmpty(command.SidebarText) && command.SidebarText.Length > 3000)
                {
                    response.Error = "The submission text cannot be greater than 1000 characters";
                    return(response);
                }

                var user = _membershipService.GetUserById(command.CreatedByUserId);

                if (user == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                var userAccountAge = Common.CurrentTime() - user.CreatedDate;
                if (!user.IsAdmin && userAccountAge.TotalDays < _subSettings.Settings.MinUserAgeCreateSub)
                {
                    response.Error = "Your account is too new to create a sub.";
                    return(response);
                }

                if (_subService.GetSubByName(command.Name) != null)
                {
                    response.Error = "The sub already exist.";
                    return(response);
                }

                if (command.Name.Equals("random", StringComparison.InvariantCultureIgnoreCase) ||
                    command.Name.Equals("all", StringComparison.InvariantCultureIgnoreCase) ||
                    Common.IsReservedKeyword(command.Name))
                {
                    response.Error = "The name is invalid.";
                    return(response);
                }

                // let's make sure the user creating this sub doesn't already have the maximum number of subs they are modding.
                var moddedSubsForUser = _moderationService.GetSubsModeratoredByUser(user.Id);
                if (moddedSubsForUser.Count >= _subSettings.Settings.MaximumNumberOfModdedSubs)
                {
                    response.Error = "You can only moderate a maximum of " + _subSettings.Settings.MaximumNumberOfModdedSubs + " subs.";
                    return(response);
                }

                var sub = new Sub
                {
                    Id                      = GuidUtil.NewSequentialId(),
                    CreatedDate             = Common.CurrentTime(),
                    Name                    = command.Name,
                    Description             = command.Description,
                    SidebarText             = command.SidebarText,
                    SidebarTextFormatted    = _markdownCompiler.Compile(command.SidebarText),
                    SubmissionText          = command.SubmissionText,
                    SubmissionTextFormatted = _markdownCompiler.Compile(command.SubmissionText),
                    SubType                 = command.Type,
                    CreatedBy               = user.Id,
                    InAll                   = command.InAll,
                    Nsfw                    = command.Nsfw
                };

                // only admins can configure default subs
                if (user.IsAdmin && command.IsDefault.HasValue)
                {
                    sub.IsDefault = command.IsDefault.Value;
                }

                _subService.InsertSub(sub);

                response.SubId   = sub.Id;
                response.SubName = sub.Name;

                _subService.SubscribeToSub(user.Id, sub.Id);
                _moderationService.AddModToSub(user.Id, sub.Id, ModeratorPermissions.All);
            }
            catch (Exception ex)
            {
                // todo: log
                response.Error = ex.Message;
            }

            return(response);
        }
Пример #7
0
        static void Main(string[] args)
        {
            try
            {
                SkimurContext.Initialize(
                    new Program(),
                    new Skimur.App.Registrar());

                _mirrorSettings    = SkimurContext.ServiceProvider.GetRequiredService <ISettingsProvider <MirrorSettings> >().Settings;
                _subService        = SkimurContext.ServiceProvider.GetRequiredService <ISubService>();
                _postService       = SkimurContext.ServiceProvider.GetRequiredService <IPostService>();
                _membershipService = SkimurContext.ServiceProvider.GetRequiredService <IMembershipService>();
                _commandBus        = SkimurContext.ServiceProvider.GetRequiredService <ICommandBus>();

                if (_mirrorSettings.SubsToMirror == null || _mirrorSettings.SubsToMirror.Count == 0)
                {
                    return;
                }

                var botUser = _membershipService.GetUserByUserName(_mirrorSettings.BotName);
                if (botUser == null)
                {
                    return;
                }

                var reddit = new Reddit();

                foreach (var subToMirror in _mirrorSettings.SubsToMirror)
                {
                    Console.WriteLine("Attempting to mirror " + subToMirror + ".");

                    var sub = _subService.GetSubByName(subToMirror);
                    if (sub == null)
                    {
                        Console.WriteLine("Sub doesn't exist.");
                        continue;
                    }

                    var redditSub = reddit.GetSubreddit("/r/" + subToMirror);
                    if (redditSub == null)
                    {
                        Console.WriteLine("Couldn't find reddit sub.");
                        continue;
                    }

                    foreach (var redditPost in redditSub.GetTop(_mirrorSettings.FromTime).Take(_mirrorSettings.PostsPerSub))
                    {
                        Console.WriteLine("Syncing " + redditPost.Title);

                        var existing = _postService.QueryPosts(redditPost.Title, sub.Id).Select(x => _postService.GetPostById(x)).ToList();
                        var exists   = false;
                        if (existing.Count > 0)
                        {
                            foreach (var item in existing)
                            {
                                if (item.Title == redditPost.Title && item.Mirrored == "reddit")
                                {
                                    exists = true;
                                }
                            }
                        }
                        if (exists)
                        {
                            Console.WriteLine("Already exists.");
                            continue;
                        }

                        var createPostResponse = _commandBus.Send <CreatePost, CreatePostResponse>(
                            new CreatePost
                        {
                            CreatedByUserId     = botUser.Id,
                            Title               = redditPost.Title,
                            Url                 = redditPost.Url.ToString(),
                            Content             = redditPost.SelfText,
                            PostType            = redditPost.IsSelfPost ? PostType.Text : PostType.Link,
                            SubName             = subToMirror,
                            NotifyReplies       = false,
                            Mirror              = "reddit",
                            OverrideDateCreated = redditPost.CreatedUTC
                        });

                        if (!string.IsNullOrEmpty(createPostResponse.Error))
                        {
                            Console.WriteLine("Couldn't create post. " + createPostResponse.Error);
                            continue;
                        }

                        if (!createPostResponse.PostId.HasValue)
                        {
                            Console.WriteLine("No post id");
                            continue;
                        }

                        var createCommentResponse = _commandBus.Send <CreateComment, CreateCommentResponse>(
                            new CreateComment
                        {
                            PostId         = createPostResponse.PostId.Value,
                            DateCreated    = Common.CurrentTime(),
                            AuthorUserName = botUser.UserName,
                            Body           = string.Format("Mirrored from [here]({0}).", redditPost.Shortlink),
                            SendReplies    = false
                        });

                        if (!string.IsNullOrEmpty(createCommentResponse.Error))
                        {
                            Console.WriteLine("Couldn't create comment. " + createCommentResponse.Error);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
Пример #8
0
        public CreatePostResponse Handle(CreatePost command)
        {
            var response = new CreatePostResponse();

            try
            {
                var user = _membershipService.GetUserById(command.CreatedByUserId);

                if (user == null)
                {
                    response.Error = "Invalid user.";
                    return(response);
                }

                if (string.IsNullOrEmpty(command.SubName))
                {
                    response.Error = "The sub name is required.";
                    return(response);
                }

                var sub = _subService.GetSubByName(command.SubName);

                if (sub == null)
                {
                    response.Error = "That sub doesn't exist.";
                    return(response);
                }

                if (!user.IsAdmin)
                {
                    // make sure the user isn't banned from this sub
                    if (_subUserBanService.IsUserBannedFromSub(sub.Id, user.Id))
                    {
                        response.Error = "You are currently banned from this sub.";
                        return(response);
                    }
                }

                // TODO: does user look like spam?

                // todo: make sure the post type is allowed

                if (string.IsNullOrEmpty(command.Title))
                {
                    response.Error = "The title is required.";
                    return(response);
                }

                // remove extrenous white space, and trim whitespace from the edges
                command.Title = Regex.Replace(command.Title, @"\s+", " ").Trim();

                if (command.Title.Length > 300)
                {
                    response.Error = "The title is too long.";
                    return(response);
                }

                string domain = null;

                if (command.PostType == PostType.Link)
                {
                    if (string.IsNullOrEmpty(command.Url))
                    {
                        response.Error = "You must provide a url.";
                        return(response);
                    }

                    // check https://github.com/skimur/skimur/issues/83
                    command.Url = command.Url.RemoveBOM();

                    // todo: improve url validation
                    string scheme;
                    string formattedUrl;
                    if (!UrlParser.TryParseUrl(command.Url, out formattedUrl, out domain, out scheme))
                    {
                        response.Error = "The url appears to be invalid.";
                        return(response);
                    }

                    command.Url = formattedUrl;

                    switch (scheme)
                    {
                    case "http":
                    case "https":
                        break;

                    default:
                        response.Error = "The scheme is invalid for the url.";
                        return(response);
                    }

                    // todo: make sure the domain isn't banned

                    // todo: make sure the url wasn't already submitted
                }
                else if (command.PostType == PostType.Text)
                {
                    if (!user.IsAdmin)
                    {
                        if (!string.IsNullOrEmpty(command.Content) && command.Content.Length > 40000)
                        {
                            response.Error = "The post content is too long (maximum 40000 characters).";
                            return(response);
                        }
                    }
                }
                else
                {
                    throw new Exception("unknown post type " + command.PostType);
                }

                bool isNsfw;

                if (sub.Nsfw)
                {
                    // NSFW by default
                    isNsfw = true;
                }
                else
                {
                    // Let's see if the user marked this as NSFW.
                    isNsfw = Common.IsNsfw(command.Title);
                }

                var post = new Post
                {
                    Id           = GuidUtil.NewSequentialId(),
                    DateCreated  = command.OverrideDateCreated.HasValue ? command.OverrideDateCreated.Value : Common.CurrentTime(),
                    LastEditDate = null,
                    SubId        = sub.Id,
                    UserId       = user.Id,
                    UserIp       = command.IpAddress,
                    PostType     = command.PostType,
                    Title        = command.Title,
                    SendReplies  = command.NotifyReplies,
                    Mirrored     = command.Mirror,
                    Nsfw         = isNsfw,
                    InAll        = sub.InAll
                };

                List <string> mentions = null;

                if (post.PostType == PostType.Link)
                {
                    post.Url    = command.Url;
                    post.Domain = domain;
                }
                else
                {
                    post.Content          = command.Content;
                    post.ContentFormatted = _markdownCompiler.Compile(post.Content, out mentions);
                }

                _postService.InsertPost(post);
                _commandBus.Send(new CastVoteForPost {
                    DateCasted = post.DateCreated, IpAddress = command.IpAddress, PostId = post.Id, UserId = user.Id, VoteType = VoteType.Up
                });

                if (mentions != null && mentions.Count > 0)
                {
                    _eventBus.Publish(new UsersMentioned {
                        PostId = post.Id, Users = mentions
                    });
                }

                _commandBus.Send(new GenerateThumbnailForPost {
                    PostId = post.Id
                });

                if (_embeddedProvider.IsEnabled)
                {
                    _commandBus.Send(new GenerateEmbeddedMediaObject {
                        PostId = post.Id
                    });
                }

                response.Title  = command.Title;
                response.PostId = post.Id;
            }
            catch (Exception ex)
            {
                // todo: log
                response.Error = ex.Message;
            }

            return(response);
        }
Пример #9
0
        static void Main(string[] args)
        {
            try
            {
                SkimurContext.Initialize(
                    new Program(),
                    new Skimur.App.Registrar());

                _mirrorSettings = SkimurContext.ServiceProvider.GetRequiredService<ISettingsProvider<MirrorSettings>>().Settings;
                _subService = SkimurContext.ServiceProvider.GetRequiredService<ISubService>();
                _postService = SkimurContext.ServiceProvider.GetRequiredService<IPostService>();
                _membershipService = SkimurContext.ServiceProvider.GetRequiredService<IMembershipService>();
                _commandBus = SkimurContext.ServiceProvider.GetRequiredService<ICommandBus>();

                if (_mirrorSettings.SubsToMirror == null || _mirrorSettings.SubsToMirror.Count == 0)
                    return;

                var botUser = _membershipService.GetUserByUserName(_mirrorSettings.BotName);
                if (botUser == null) return;

                var reddit = new Reddit();

                foreach (var subToMirror in _mirrorSettings.SubsToMirror)
                {
                    Console.WriteLine("Attempting to mirror " + subToMirror + ".");

                    var sub = _subService.GetSubByName(subToMirror);
                    if (sub == null)
                    {
                        Console.WriteLine("Sub doesn't exist.");
                        continue;
                    }

                    var redditSub = reddit.GetSubreddit("/r/" + subToMirror);
                    if (redditSub == null)
                    {
                        Console.WriteLine("Couldn't find reddit sub.");
                        continue;
                    }

                    foreach (var redditPost in redditSub.GetTop(_mirrorSettings.FromTime).Take(_mirrorSettings.PostsPerSub))
                    {
                        Console.WriteLine("Syncing " + redditPost.Title);

                        var existing = _postService.QueryPosts(redditPost.Title, sub.Id).Select(x => _postService.GetPostById(x)).ToList();
                        var exists = false;
                        if (existing.Count > 0)
                        {
                            foreach (var item in existing)
                            {
                                if (item.Title == redditPost.Title && item.Mirrored == "reddit")
                                    exists = true;
                            }
                        }
                        if (exists)
                        {
                            Console.WriteLine("Already exists.");
                            continue;
                        }

                        var createPostResponse = _commandBus.Send<CreatePost, CreatePostResponse>(
                            new CreatePost
                            {
                                CreatedByUserId = botUser.Id,
                                Title = redditPost.Title,
                                Url = redditPost.Url.ToString(),
                                Content = redditPost.SelfText,
                                PostType = redditPost.IsSelfPost ? PostType.Text : PostType.Link,
                                SubName = subToMirror,
                                NotifyReplies = false,
                                Mirror = "reddit",
                                OverrideDateCreated = redditPost.CreatedUTC
                            });

                        if (!string.IsNullOrEmpty(createPostResponse.Error))
                        {
                            Console.WriteLine("Couldn't create post. " + createPostResponse.Error);
                            continue;
                        }

                        if (!createPostResponse.PostId.HasValue)
                        {
                            Console.WriteLine("No post id");
                            continue;
                        }

                        var createCommentResponse = _commandBus.Send<CreateComment, CreateCommentResponse>(
                           new CreateComment
                           {
                               PostId = createPostResponse.PostId.Value,
                               DateCreated = Common.CurrentTime(),
                               AuthorUserName = botUser.UserName,
                               Body = string.Format("Mirrored from [here]({0}).", redditPost.Shortlink),
                               SendReplies = false
                           });

                        if (!string.IsNullOrEmpty(createCommentResponse.Error))
                        {
                            Console.WriteLine("Couldn't create comment. " + createCommentResponse.Error);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
Пример #10
0
        public SendMessageResponse Handle(SendMessage command)
        {
            var response = new SendMessageResponse();

            try
            {
                var author = _membershipService.GetUserById(command.Author);

                if (author == null)
                {
                    response.Error = "No author provided.";
                    return(response);
                }

                Sub  sendAsSub     = null;
                Sub  sendingToSub  = null;
                User sendingToUser = null;

                if (command.SendAsSub.HasValue)
                {
                    var sub = _subService.GetSubById(command.SendAsSub.Value);

                    if (sub == null)
                    {
                        response.Error = "Invalid sub to send as.";
                        return(response);
                    }

                    // the user is trying to send this message as a sub moderator.
                    // let's make sure that this user has this permission for the sub.
                    if (!_permissionService.CanUserManageSubMail(author, command.SendAsSub.Value))
                    {
                        response.Error = "You are not authorized to send a message as a sub moderator.";
                        return(response);
                    }

                    sendAsSub = sub;
                }

                if (string.IsNullOrEmpty(command.To) && !command.ToUserId.HasValue)
                {
                    response.Error = "You must provide a user/sub to send the message to.";
                    return(response);
                }

                if (command.ToUserId.HasValue && !string.IsNullOrEmpty(command.To))
                {
                    throw new Exception("A message with a userid and to was provided. Pick one.");
                }

                if (command.ToUserId.HasValue)
                {
                    sendingToUser = _membershipService.GetUserById(command.ToUserId.Value);
                    if (sendingToUser == null)
                    {
                        response.Error = "No user found to send message to.";
                        return(response);
                    }
                }
                else
                {
                    if (command.To.StartsWith("/u/", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var userName = command.To.Substring(3);
                        sendingToUser = _membershipService.GetUserByUserName(userName);
                        if (sendingToUser == null)
                        {
                            response.Error = string.Format("No user found with the name {0}.", userName);
                            return(response);
                        }
                    }
                    else if (command.To.StartsWith("/s/", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var subName = command.To.Substring(3);
                        sendingToSub = _subService.GetSubByName(subName);
                        if (sendingToSub == null)
                        {
                            response.Error = string.Format("No sub found with the name {0}.", subName);
                            return(response);
                        }
                    }
                    else
                    {
                        // maybe they are trying to send a message to a user
                        sendingToUser = _membershipService.GetUserByUserName(command.To);
                        if (sendingToUser == null)
                        {
                            response.Error = string.Format("No user found with the name {0}.", command.To);
                            return(response);
                        }
                    }
                }

                // let's make sure the message type is correct
                switch (command.Type)
                {
                case MessageType.Private:
                    if (command.CommentId.HasValue)
                    {
                        throw new Exception("A privat message was sent with a reference to a comment id. How?");
                    }
                    break;

                case MessageType.CommentReply:
                    if (!command.CommentId.HasValue)
                    {
                        throw new Exception("The message type was a comment reply, but no comment id was given.");
                    }
                    break;

                case MessageType.PostReply:
                    if (!command.CommentId.HasValue)
                    {
                        throw new Exception("The message type was a post reply, but no comment id was given.");
                    }
                    break;

                case MessageType.Mention:
                    // ensure either 1 comment is given, or 1 post is given
                    if (!command.CommentId.HasValue && !command.PostId.HasValue)
                    {
                        throw new Exception("The message type was a mention, but neither a comment or a post was given.");
                    }
                    if (command.PostId.HasValue && command.CommentId.HasValue)
                    {
                        throw new Exception("The message type was a mention, but both a comment and post were given. Pick one.");
                    }
                    break;

                default:
                    throw new Exception("Unknown message type");
                }

                var message = new Message
                {
                    Id            = GuidUtil.NewSequentialId(),
                    DateCreated   = Common.CurrentTime(),
                    MessageType   = command.Type,
                    ParentId      = null,
                    FirstMessage  = null,
                    AuthorId      = author.Id,
                    AuthorIp      = command.AuthorIp,
                    IsNew         = true,
                    ToUser        = sendingToUser != null ? sendingToUser.Id : (Guid?)null,
                    ToSub         = sendingToSub != null ? sendingToSub.Id : (Guid?)null,
                    FromSub       = sendAsSub != null ? sendAsSub.Id : (Guid?)null,
                    Subject       = command.Subject,
                    Body          = command.Body,
                    BodyFormatted = _markdownCompiler.Compile(command.Body),
                    CommentId     = command.CommentId,
                    PostId        = command.PostId
                };

                _messageService.InsertMessage(message);

                response.MessageId = message.Id;
            }
            catch (Exception ex)
            {
                _logger.Error("Error sending a message.", ex);
                response.Error = "An unknown error occured.";
            }

            return(response);
        }