void AccountGroupsInvite_Save(object sender, EventArgs e)
        {
            AuthoriseRequestSid();

            long groupId = core.Functions.FormLong("id", 0);

            try
            {
                UserGroup thisGroup = new UserGroup(core, groupId);

                try
                {
                    long userId = UserSelectBox.FormUser(core, "username", 0);

                    core.LoadUserProfile(userId);
                    User inviteMember = core.PrimitiveCache[userId];

                    if (!inviteMember.IsFriend(LoggedInMember.ItemKey))
                    {
                        core.Display.ShowMessage("Error", "You can only invite mutual friends to groups.");
                        return;
                    }

                    if (!thisGroup.IsGroupMember(LoggedInMember.ItemKey))
                    {
                        core.Display.ShowMessage("Error", "You must be a member of a group to invite someone to it.");
                        return;
                    }

                    if (!thisGroup.IsGroupMember(inviteMember.ItemKey))
                    {
                        // use their relation, otherwise you could just create a billion pending friends and still SPAM them with group invites
                        DataTable friendsTable = db.Query(string.Format("SELECT relation_time_ut FROM user_relations WHERE relation_me = {0} AND relation_you = {1} AND relation_type = 'FRIEND';",
                            inviteMember.UserId, LoggedInMember.Id));

                        if (friendsTable.Rows.Count > 0)
                        {
                            ApplicationEntry ae = Application.GetExecutingApplication(core, LoggedInMember);
                            ae.SendNotification(core, LoggedInMember, inviteMember, thisGroup.ItemKey, thisGroup.ItemKey, "_INVITED_YOU_TO_JOIN_A_GROUP", thisGroup.Uri, "invite");

                            SetRedirectUri(thisGroup.Uri);
                            core.Display.ShowMessage("Invited Friend", "You have invited a friend to the group.");
                        }
                        else
                        {
                            SetError("You can only invite people who are friends with you to join a group.");
                            return;
                        }
                    }
                    else
                    {
                        SetError("The person you are trying to invite is already a member of the group. An invitation has not been sent.");
                        return;
                    }
                }
                catch (InvalidUserException)
                {
                    SetError("The user you have entered does not exist.");
                    return;
                }
            }
            catch (InvalidGroupException)
            {
                DisplayGenericError();
                return;
            }
        }
        void AccountGroupsInvite_Show(object sender, EventArgs e)
        {
            SetTemplate("account_group_invite");

            long groupId = core.Functions.RequestLong("id", 0);

            try
            {
                UserGroup thisGroup = new UserGroup(core, groupId);

                if (!thisGroup.IsGroupMember(LoggedInMember.ItemKey))
                {
                    core.Display.ShowMessage("Error", "You must be a member of a group to invite someone to it.");
                    return;
                }

                switch (thisGroup.GroupType)
                {
                    case "OPEN":
                    case "REQUEST":
                    case "CLOSED":
                    case "PRIVATE":
                        break;
                }

                UserSelectBox inviteUserSelectBox = new UserSelectBox(core, "username");
                inviteUserSelectBox.SelectMultiple = false;

                template.Parse("S_USERNAME", inviteUserSelectBox);
                template.Parse("S_ID", groupId.ToString());
            }
            catch (InvalidGroupException)
            {
                DisplayGenericError();
            }

            Save(new EventHandler(AccountGroupsInvite_Save));
        }
        void AccountGroupsMembershipsManage_MakeOfficer(object sender, ModuleModeEventArgs e)
        {
            SetTemplate("account_group_appoint_officer");

            long groupId;
            long userId;

            try
            {
                string[] idString = core.Http.Query["id"].Split(new char[] { ',' });
                groupId = long.Parse(idString[0]);
                userId = long.Parse(idString[1]);
            }
            catch
            {
                DisplayGenericError();
                return;
            }

            try
            {
                UserGroup thisGroup = new UserGroup(core, groupId);

                if (thisGroup.IsGroupOperator(LoggedInMember.ItemKey))
                {
                    try
                    {
                        User member = new User(core, userId);

                        if (thisGroup.IsGroupMember(member.ItemKey))
                        {
                            // all ok, don't really need to do much, so let's do it
                            template.Parse("S_ID", string.Format("{0},{1}", groupId, userId));
                            template.Parse("S_USERNAME", member.UserName);
                        }
                        else
                        {
                            core.Functions.ThrowError();
                            return;
                        }
                    }
                    catch
                    {
                        core.Functions.ThrowError();
                        return;
                    }
                }
                else
                {
                    core.Display.ShowMessage("Unauthorised", "You must be the group operator to appoint an operator.");
                    return;
                }
            }
            catch
            {
                core.Functions.ThrowError();
                return;
            }
        }
        void AccountGroupsMembershipsManage_MakeOfficer_Save(object sender, EventArgs e)
        {
            long groupId = 0;
            long userId = 0;
            string title;

            try
            {
                string[] idString = core.Http.Form["id"].Split(new char[] { ',' });
                groupId = long.Parse(idString[0]);
                userId = long.Parse(idString[1]);
                title = core.Http.Form["title"];
            }
            catch
            {
                core.Functions.ThrowError();
                return;
            }

            if (string.IsNullOrEmpty(title))
            {
                core.Display.ShowMessage("Officer Title Empty", "The officer title must not be empty, go back and enter an officer title.");
                return;
            }
            else
            {
                if (title.Length < 4)
                {
                    core.Display.ShowMessage("Officer Title Too Short", "The officer title must be at least four characters, go back and enter an officer title.");
                    return;
                }
                else if (title.Length > 24)
                {
                    core.Display.ShowMessage("Officer Title Too Long", "The officer title must be at most twenty four characters, go back and enter an officer title.");
                    return;
                }
            }

            try
            {
                UserGroup thisGroup = new UserGroup(core, groupId);

                if (thisGroup.IsGroupOperator(LoggedInMember.ItemKey))
                {
                    try
                    {
                        User member = new User(core, userId);

                        if (thisGroup.IsGroupMember(member.ItemKey))
                        {
                            // allow to be an officer to many things
                            db.BeginTransaction();
                            long status = db.UpdateQuery(string.Format("INSERT INTO group_officers (group_id, user_id, officer_title) VALUES ({0}, {1}, '{2}');",
                                thisGroup.GroupId, member.UserId, Mysql.Escape(title)));

                            if (status >= 0)
                            {
                                db.UpdateQuery(string.Format("UPDATE group_info SET group_officers = group_officers + 1 WHERE group_id = {0}",
                                    thisGroup.GroupId));

                                SetRedirectUri(thisGroup.Uri);
                                core.Display.ShowMessage("Officer Appointed to Group", "You have successfully appointed an officer to the group.");
                            }
                            else
                            {
                                core.Display.ShowMessage("Already Officer", "This member is already appointed as this officer.");
                                return;
                            }
                        }
                        else
                        {
                            core.Functions.ThrowError();
                            return;
                        }
                    }
                    catch
                    {
                        core.Functions.ThrowError();
                        return;
                    }
                }
                else
                {
                    core.Display.ShowMessage("Unauthorised", "You must be the group operator to appoint an officer.");
                    return;
                }
            }
            catch
            {
                core.Functions.ThrowError();
                return;
            }
        }
        void AccountGroupsMembershipsManage_Leave(object sender, ModuleModeEventArgs e)
        {
            AuthoriseRequestSid();

            long groupId = 0;

            try
            {
                groupId = long.Parse(core.Http.Query["id"]);
            }
            catch
            {
                core.Display.ShowMessage("Error", "Unable to complete action, missing data. Go back and try again.");
                return;
            }

            try
            {
                UserGroup thisGroup = new UserGroup(core, groupId);

                bool isGroupMemberPending = thisGroup.IsGroupMemberPending(LoggedInMember.ItemKey);
                bool isGroupMember = thisGroup.IsGroupMember(LoggedInMember.ItemKey);

                DataTable operatorsTable = db.Query(string.Format("SELECT user_id FROM group_operators WHERE group_id = {0} AND user_id = {1};",
                    thisGroup.GroupId, LoggedInMember.Id));

                if (operatorsTable.Rows.Count > 0)
                {
                    SetRedirectUri(thisGroup.Uri);
                    core.Display.ShowMessage("Cannot Leave Group", "You cannot leave this group while you are an operator of the group.");
                    return;
                }
                else
                {
                    if (isGroupMember)
                    {
                        db.BeginTransaction();
                        db.UpdateQuery(string.Format("DELETE FROM group_members WHERE group_id = {0} AND user_id = {1};",
                            thisGroup.GroupId, LoggedInMember.Id));

                        long officerRowsChanged = db.UpdateQuery(string.Format("DELETE FROM group_officers WHERE group_id = {0} AND user_id = {1};",
                            thisGroup.GroupId, LoggedInMember.Id));

                        db.UpdateQuery(string.Format("UPDATE group_info SET group_members = group_members - 1, group_officers = group_officers - {1} WHERE group_id = {0}",
                            thisGroup.GroupId, officerRowsChanged));

                        SetRedirectUri(thisGroup.Uri);
                        core.Display.ShowMessage("Left Group", "You have left the group.");
                        return;
                    }
                    else if (isGroupMemberPending)
                    {
                        db.UpdateQuery(string.Format("DELETE FROM group_members WHERE group_id = {0} AND user_id = {1};",
                            thisGroup.GroupId, LoggedInMember.UserId));

                        SetRedirectUri(thisGroup.Uri);
                        core.Display.ShowMessage("Left Group", "You are no longer pending membership of the group.");
                        return;
                    }
                    else
                    {
                        SetRedirectUri(thisGroup.Uri);
                        core.Display.ShowMessage("Not a Member", "You cannot leave a group you are not a member of.");
                        return;
                    }
                }
            }
            catch (InvalidGroupException)
            {
                core.Display.ShowMessage("Group does not Exist", "The group you are trying to leave does not exist.");
                return;
            }
        }