aboutsummaryrefslogtreecommitdiff
path: root/mod/groups
diff options
context:
space:
mode:
Diffstat (limited to 'mod/groups')
-rw-r--r--mod/groups/actions/discussion/delete.php29
-rw-r--r--mod/groups/actions/discussion/reply/delete.php26
-rw-r--r--mod/groups/actions/discussion/reply/save.php58
-rw-r--r--mod/groups/actions/discussion/save.php75
-rw-r--r--mod/groups/actions/groups/delete.php42
-rw-r--r--mod/groups/actions/groups/edit.php235
-rw-r--r--mod/groups/actions/groups/featured.php27
-rw-r--r--mod/groups/actions/groups/membership/add.php42
-rw-r--r--mod/groups/actions/groups/membership/delete_invite.php24
-rw-r--r--mod/groups/actions/groups/membership/delete_request.php20
-rw-r--r--mod/groups/actions/groups/membership/invite.php56
-rw-r--r--mod/groups/actions/groups/membership/join.php72
-rw-r--r--mod/groups/actions/groups/membership/leave.php36
-rw-r--r--mod/groups/actions/groups/membership/remove.php31
-rw-r--r--mod/groups/graphics/defaultlarge.gifbin0 -> 4939 bytes
-rw-r--r--mod/groups/graphics/defaultmedium.gifbin0 -> 2336 bytes
-rw-r--r--mod/groups/graphics/defaultsmall.gifbin0 -> 1127 bytes
-rw-r--r--mod/groups/graphics/defaulttiny.gifbin0 -> 782 bytes
-rw-r--r--mod/groups/icon.php54
-rw-r--r--mod/groups/languages/en.php299
-rw-r--r--mod/groups/lib/discussion.php235
-rw-r--r--mod/groups/lib/groups.php590
-rw-r--r--mod/groups/manifest.xml18
-rw-r--r--mod/groups/start.php1073
-rw-r--r--mod/groups/topicposts.php19
-rw-r--r--mod/groups/upgrades/2011030101.php66
-rw-r--r--mod/groups/views/default/annotation/group_topic_post.php19
-rw-r--r--mod/groups/views/default/discussion/closed.php6
-rw-r--r--mod/groups/views/default/discussion/group_module.php48
-rw-r--r--mod/groups/views/default/discussion/replies.php28
-rw-r--r--mod/groups/views/default/forms/discussion/reply/save.php57
-rw-r--r--mod/groups/views/default/forms/discussion/save.php57
-rw-r--r--mod/groups/views/default/forms/groups/edit.php178
-rw-r--r--mod/groups/views/default/forms/groups/find.php16
-rw-r--r--mod/groups/views/default/forms/groups/invite.php22
-rw-r--r--mod/groups/views/default/forms/groups/search.php20
-rw-r--r--mod/groups/views/default/group/default.php37
-rw-r--r--mod/groups/views/default/groups/css.php76
-rw-r--r--mod/groups/views/default/groups/edit.php15
-rw-r--r--mod/groups/views/default/groups/group_sort_menu.php36
-rw-r--r--mod/groups/views/default/groups/invitationrequests.php51
-rw-r--r--mod/groups/views/default/groups/js.php13
-rw-r--r--mod/groups/views/default/groups/membershiprequests.php47
-rw-r--r--mod/groups/views/default/groups/profile/activity_module.php44
-rw-r--r--mod/groups/views/default/groups/profile/closed_membership.php16
-rw-r--r--mod/groups/views/default/groups/profile/fields.php38
-rw-r--r--mod/groups/views/default/groups/profile/layout.php13
-rw-r--r--mod/groups/views/default/groups/profile/module.php25
-rw-r--r--mod/groups/views/default/groups/profile/summary.php64
-rw-r--r--mod/groups/views/default/groups/profile/widgets.php24
-rw-r--r--mod/groups/views/default/groups/sidebar/featured.php25
-rw-r--r--mod/groups/views/default/groups/sidebar/find.php14
-rw-r--r--mod/groups/views/default/groups/sidebar/members.php32
-rw-r--r--mod/groups/views/default/groups/sidebar/my_status.php62
-rw-r--r--mod/groups/views/default/groups/sidebar/search.php15
-rw-r--r--mod/groups/views/default/object/groupforumtopic.php101
-rw-r--r--mod/groups/views/default/plugins/groups/settings.php40
-rw-r--r--mod/groups/views/default/river/annotation/group_topic_post/reply.php12
-rw-r--r--mod/groups/views/default/river/group/create.php13
-rw-r--r--mod/groups/views/default/river/object/groupforumtopic/create.php22
-rw-r--r--mod/groups/views/default/river/relationship/member/create.php8
-rw-r--r--mod/groups/views/default/widgets/a_users_groups/content.php33
-rw-r--r--mod/groups/views/default/widgets/a_users_groups/edit.php25
-rw-r--r--mod/groups/views/rss/annotation/group_topic_post.php32
-rw-r--r--mod/groups/views/rss/discussion/replies.php12
-rw-r--r--mod/groups/views/rss/groups/profile/layout.php18
-rw-r--r--mod/groups/views/rss/object/groupforumtopic.php35
67 files changed, 4576 insertions, 0 deletions
diff --git a/mod/groups/actions/discussion/delete.php b/mod/groups/actions/discussion/delete.php
new file mode 100644
index 000000000..f307aa091
--- /dev/null
+++ b/mod/groups/actions/discussion/delete.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Delete topic action
+ *
+ */
+
+$topic_guid = (int) get_input('guid');
+
+$topic = get_entity($topic_guid);
+if (!$topic || !$topic->getSubtype() == "groupforumtopic") {
+ register_error(elgg_echo('discussion:error:notdeleted'));
+ forward(REFERER);
+}
+
+if (!$topic->canEdit()) {
+ register_error(elgg_echo('discussion:error:permissions'));
+ forward(REFERER);
+}
+
+$container = $topic->getContainerEntity();
+
+$result = $topic->delete();
+if ($result) {
+ system_message(elgg_echo('discussion:topic:deleted'));
+} else {
+ register_error(elgg_echo('discussion:error:notdeleted'));
+}
+
+forward("discussion/owner/$container->guid");
diff --git a/mod/groups/actions/discussion/reply/delete.php b/mod/groups/actions/discussion/reply/delete.php
new file mode 100644
index 000000000..88c6b79d6
--- /dev/null
+++ b/mod/groups/actions/discussion/reply/delete.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Delete discussion reply
+ */
+
+$id = (int) get_input('annotation_id');
+
+$reply = elgg_get_annotation_from_id($id);
+if (!$reply || $reply->name != 'group_topic_post') {
+ register_error(elgg_echo('discussion:reply:error:notdeleted'));
+ forward(REFERER);
+}
+
+if (!$reply->canEdit()) {
+ register_error(elgg_echo('discussion:error:permissions'));
+ forward(REFERER);
+}
+
+$result = $reply->delete();
+if ($result) {
+ system_message(elgg_echo('discussion:reply:deleted'));
+} else {
+ register_error(elgg_echo('discussion:reply:error:notdeleted'));
+}
+
+forward(REFERER);
diff --git a/mod/groups/actions/discussion/reply/save.php b/mod/groups/actions/discussion/reply/save.php
new file mode 100644
index 000000000..f8be8aa2c
--- /dev/null
+++ b/mod/groups/actions/discussion/reply/save.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Post a reply to discussion topic
+ *
+ */
+
+// Get input
+$entity_guid = (int) get_input('entity_guid');
+$text = get_input('group_topic_post');
+$annotation_id = (int) get_input('annotation_id');
+
+// reply cannot be empty
+if (empty($text)) {
+ register_error(elgg_echo('grouppost:nopost'));
+ forward(REFERER);
+}
+
+$topic = get_entity($entity_guid);
+if (!$topic) {
+ register_error(elgg_echo('grouppost:nopost'));
+ forward(REFERER);
+}
+
+$user = elgg_get_logged_in_user_entity();
+
+$group = $topic->getContainerEntity();
+if (!$group->canWriteToContainer()) {
+ register_error(elgg_echo('groups:notmember'));
+ forward(REFERER);
+}
+
+// if editing a reply, make sure it's valid
+if ($annotation_id) {
+ $annotation = elgg_get_annotation_from_id($annotation_id);
+ if (!$annotation->canEdit()) {
+ register_error(elgg_echo('groups:notowner'));
+ forward(REFERER);
+ }
+
+ $annotation->value = $text;
+ if (!$annotation->save()) {
+ system_message(elgg_echo('groups:forumpost:error'));
+ forward(REFERER);
+ }
+ system_message(elgg_echo('groups:forumpost:edited'));
+} else {
+ // add the reply to the forum topic
+ $reply_id = $topic->annotate('group_topic_post', $text, $topic->access_id, $user->guid);
+ if ($reply_id == false) {
+ system_message(elgg_echo('groupspost:failure'));
+ forward(REFERER);
+ }
+
+ add_to_river('river/annotation/group_topic_post/reply', 'reply', $user->guid, $topic->guid, "", 0, $reply_id);
+ system_message(elgg_echo('groupspost:success'));
+}
+
+forward(REFERER);
diff --git a/mod/groups/actions/discussion/save.php b/mod/groups/actions/discussion/save.php
new file mode 100644
index 000000000..b3e9da654
--- /dev/null
+++ b/mod/groups/actions/discussion/save.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Topic save action
+ */
+
+// Get variables
+$title = htmlspecialchars(get_input('title', '', false), ENT_QUOTES, 'UTF-8');
+$desc = get_input("description");
+$status = get_input("status");
+$access_id = (int) get_input("access_id");
+$container_guid = (int) get_input('container_guid');
+$guid = (int) get_input('topic_guid');
+$tags = get_input("tags");
+
+elgg_make_sticky_form('topic');
+
+// validation of inputs
+if (!$title || !$desc) {
+ register_error(elgg_echo('discussion:error:missing'));
+ forward(REFERER);
+}
+
+$container = get_entity($container_guid);
+if (!$container || !$container->canWriteToContainer(0, 'object', 'groupforumtopic')) {
+ register_error(elgg_echo('discussion:error:permissions'));
+ forward(REFERER);
+}
+
+// check whether this is a new topic or an edit
+$new_topic = true;
+if ($guid > 0) {
+ $new_topic = false;
+}
+
+if ($new_topic) {
+ $topic = new ElggObject();
+ $topic->subtype = 'groupforumtopic';
+} else {
+ // load original file object
+ $topic = new ElggObject($guid);
+ if (!$topic || !$topic->canEdit()) {
+ register_error(elgg_echo('discussion:topic:notfound'));
+ forward(REFERER);
+ }
+}
+
+$topic->title = $title;
+$topic->description = $desc;
+$topic->status = $status;
+$topic->access_id = $access_id;
+$topic->container_guid = $container_guid;
+
+$tags = explode(",", $tags);
+$topic->tags = $tags;
+
+$result = $topic->save();
+
+if (!$result) {
+ register_error(elgg_echo('discussion:error:notsaved'));
+ forward(REFERER);
+}
+
+// topic saved so clear sticky form
+elgg_clear_sticky_form('topic');
+
+
+// handle results differently for new topics and topic edits
+if ($new_topic) {
+ system_message(elgg_echo('discussion:topic:created'));
+ add_to_river('river/object/groupforumtopic/create', 'create', elgg_get_logged_in_user_guid(), $topic->guid);
+} else {
+ system_message(elgg_echo('discussion:topic:updated'));
+}
+
+forward($topic->getURL());
diff --git a/mod/groups/actions/groups/delete.php b/mod/groups/actions/groups/delete.php
new file mode 100644
index 000000000..2ff6c339c
--- /dev/null
+++ b/mod/groups/actions/groups/delete.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Delete a group
+ */
+
+$guid = (int) get_input('guid');
+if (!$guid) {
+ // backward compatible
+ elgg_deprecated_notice("Use 'guid' for group delete action", 1.8);
+ $guid = (int)get_input('group_guid');
+}
+$entity = get_entity($guid);
+
+if (!$entity->canEdit()) {
+ register_error(elgg_echo('group:notdeleted'));
+ forward(REFERER);
+}
+
+if (($entity) && ($entity instanceof ElggGroup)) {
+ // delete group icons
+ $owner_guid = $entity->owner_guid;
+ $prefix = "groups/" . $entity->guid;
+ $imagenames = array('.jpg', 'tiny.jpg', 'small.jpg', 'medium.jpg', 'large.jpg');
+ $img = new ElggFile();
+ $img->owner_guid = $owner_guid;
+ foreach ($imagenames as $name) {
+ $img->setFilename($prefix . $name);
+ $img->delete();
+ }
+
+ // delete group
+ if ($entity->delete()) {
+ system_message(elgg_echo('group:deleted'));
+ } else {
+ register_error(elgg_echo('group:notdeleted'));
+ }
+} else {
+ register_error(elgg_echo('group:notdeleted'));
+}
+
+$url_name = elgg_get_logged_in_user_entity()->username;
+forward(elgg_get_site_url() . "groups/member/{$url_name}");
diff --git a/mod/groups/actions/groups/edit.php b/mod/groups/actions/groups/edit.php
new file mode 100644
index 000000000..f19b90566
--- /dev/null
+++ b/mod/groups/actions/groups/edit.php
@@ -0,0 +1,235 @@
+<?php
+/**
+ * Elgg groups plugin edit action.
+ *
+ * @package ElggGroups
+ */
+
+elgg_make_sticky_form('groups');
+
+/**
+ * wrapper for recursive array walk decoding
+ */
+function profile_array_decoder(&$v) {
+ $v = _elgg_html_decode($v);
+}
+
+// Get group fields
+$input = array();
+foreach (elgg_get_config('group') as $shortname => $valuetype) {
+ $input[$shortname] = get_input($shortname);
+
+ // @todo treat profile fields as unescaped: don't filter, encode on output
+ if (is_array($input[$shortname])) {
+ array_walk_recursive($input[$shortname], 'profile_array_decoder');
+ } else {
+ $input[$shortname] = _elgg_html_decode($input[$shortname]);
+ }
+
+ if ($valuetype == 'tags') {
+ $input[$shortname] = string_to_tag_array($input[$shortname]);
+ }
+}
+
+$input['name'] = htmlspecialchars(get_input('name', '', false), ENT_QUOTES, 'UTF-8');
+
+$user = elgg_get_logged_in_user_entity();
+
+$group_guid = (int)get_input('group_guid');
+$is_new_group = $group_guid == 0;
+
+if ($is_new_group
+ && (elgg_get_plugin_setting('limited_groups', 'groups') == 'yes')
+ && !$user->isAdmin()) {
+ register_error(elgg_echo("groups:cantcreate"));
+ forward(REFERER);
+}
+
+$group = new ElggGroup($group_guid); // load if present, if not create a new group
+if ($group_guid && !$group->canEdit()) {
+ register_error(elgg_echo("groups:cantedit"));
+ forward(REFERER);
+}
+
+// Assume we can edit or this is a new group
+if (sizeof($input) > 0) {
+ foreach($input as $shortname => $value) {
+ // update access collection name if group name changes
+ if (!$is_new_group && $shortname == 'name' && $value != $group->name) {
+ $group_name = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
+ $ac_name = sanitize_string(elgg_echo('groups:group') . ": " . $group_name);
+ $acl = get_access_collection($group->group_acl);
+ if ($acl) {
+ // @todo Elgg api does not support updating access collection name
+ $db_prefix = elgg_get_config('dbprefix');
+ $query = "UPDATE {$db_prefix}access_collections SET name = '$ac_name'
+ WHERE id = $group->group_acl";
+ update_data($query);
+ }
+ }
+
+ $group->$shortname = $value;
+ }
+}
+
+// Validate create
+if (!$group->name) {
+ register_error(elgg_echo("groups:notitle"));
+ forward(REFERER);
+}
+
+
+// Set group tool options
+$tool_options = elgg_get_config('group_tool_options');
+if ($tool_options) {
+ foreach ($tool_options as $group_option) {
+ $option_toggle_name = $group_option->name . "_enable";
+ $option_default = $group_option->default_on ? 'yes' : 'no';
+ $group->$option_toggle_name = get_input($option_toggle_name, $option_default);
+ }
+}
+
+// Group membership - should these be treated with same constants as access permissions?
+$is_public_membership = (get_input('membership') == ACCESS_PUBLIC);
+$group->membership = $is_public_membership ? ACCESS_PUBLIC : ACCESS_PRIVATE;
+
+if ($is_new_group) {
+ $group->access_id = ACCESS_PUBLIC;
+}
+
+$old_owner_guid = $is_new_group ? 0 : $group->owner_guid;
+$new_owner_guid = (int) get_input('owner_guid');
+
+$owner_has_changed = false;
+$old_icontime = null;
+if (!$is_new_group && $new_owner_guid && $new_owner_guid != $old_owner_guid) {
+ // verify new owner is member and old owner/admin is logged in
+ if (is_group_member($group_guid, $new_owner_guid) && ($old_owner_guid == $user->guid || $user->isAdmin())) {
+ $group->owner_guid = $new_owner_guid;
+ $group->container_guid = $new_owner_guid;
+
+ $metadata = elgg_get_metadata(array(
+ 'guid' => $group_guid,
+ 'limit' => false,
+ ));
+ if ($metadata) {
+ foreach ($metadata as $md) {
+ if ($md->owner_guid == $old_owner_guid) {
+ $md->owner_guid = $new_owner_guid;
+ $md->save();
+ }
+ }
+ }
+
+ // @todo Remove this when #4683 fixed
+ $owner_has_changed = true;
+ $old_icontime = $group->icontime;
+ }
+}
+
+$must_move_icons = ($owner_has_changed && $old_icontime);
+
+$group->save();
+
+// Invisible group support
+// @todo this requires save to be called to create the acl for the group. This
+// is an odd requirement and should be removed. Either the acl creation happens
+// in the action or the visibility moves to a plugin hook
+if (elgg_get_plugin_setting('hidden_groups', 'groups') == 'yes') {
+ $visibility = (int)get_input('vis', '', false);
+ if ($visibility != ACCESS_PUBLIC && $visibility != ACCESS_LOGGED_IN) {
+ $visibility = $group->group_acl;
+ }
+
+ if ($group->access_id != $visibility) {
+ $group->access_id = $visibility;
+ }
+}
+
+$group->save();
+
+// group saved so clear sticky form
+elgg_clear_sticky_form('groups');
+
+// group creator needs to be member of new group and river entry created
+if ($is_new_group) {
+
+ // @todo this should not be necessary...
+ elgg_set_page_owner_guid($group->guid);
+
+ $group->join($user);
+ add_to_river('river/group/create', 'create', $user->guid, $group->guid, $group->access_id);
+}
+
+$has_uploaded_icon = (!empty($_FILES['icon']['type']) && substr_count($_FILES['icon']['type'], 'image/'));
+
+if ($has_uploaded_icon) {
+
+ $icon_sizes = elgg_get_config('icon_sizes');
+
+ $prefix = "groups/" . $group->guid;
+
+ $filehandler = new ElggFile();
+ $filehandler->owner_guid = $group->owner_guid;
+ $filehandler->setFilename($prefix . ".jpg");
+ $filehandler->open("write");
+ $filehandler->write(get_uploaded_file('icon'));
+ $filehandler->close();
+ $filename = $filehandler->getFilenameOnFilestore();
+
+ $sizes = array('tiny', 'small', 'medium', 'large');
+
+ $thumbs = array();
+ foreach ($sizes as $size) {
+ $thumbs[$size] = get_resized_image_from_existing_file(
+ $filename,
+ $icon_sizes[$size]['w'],
+ $icon_sizes[$size]['h'],
+ $icon_sizes[$size]['square']
+ );
+ }
+
+ if ($thumbs['tiny']) { // just checking if resize successful
+ $thumb = new ElggFile();
+ $thumb->owner_guid = $group->owner_guid;
+ $thumb->setMimeType('image/jpeg');
+
+ foreach ($sizes as $size) {
+ $thumb->setFilename("{$prefix}{$size}.jpg");
+ $thumb->open("write");
+ $thumb->write($thumbs[$size]);
+ $thumb->close();
+ }
+
+ $group->icontime = time();
+ }
+}
+
+// @todo Remove this when #4683 fixed
+if ($must_move_icons) {
+ $filehandler = new ElggFile();
+ $filehandler->setFilename('groups');
+ $filehandler->owner_guid = $old_owner_guid;
+ $old_path = $filehandler->getFilenameOnFilestore();
+
+ $sizes = array('', 'tiny', 'small', 'medium', 'large');
+
+ if ($has_uploaded_icon) {
+ // delete those under old owner
+ foreach ($sizes as $size) {
+ unlink("$old_path/{$group_guid}{$size}.jpg");
+ }
+ } else {
+ // move existing to new owner
+ $filehandler->owner_guid = $group->owner_guid;
+ $new_path = $filehandler->getFilenameOnFilestore();
+
+ foreach ($sizes as $size) {
+ rename("$old_path/{$group_guid}{$size}.jpg", "$new_path/{$group_guid}{$size}.jpg");
+ }
+ }
+}
+
+system_message(elgg_echo("groups:saved"));
+
+forward($group->getUrl());
diff --git a/mod/groups/actions/groups/featured.php b/mod/groups/actions/groups/featured.php
new file mode 100644
index 000000000..4cb9f8122
--- /dev/null
+++ b/mod/groups/actions/groups/featured.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Feature a group
+ *
+ * @package ElggGroups
+ */
+
+$group_guid = get_input('group_guid');
+$action = get_input('action_type');
+
+$group = get_entity($group_guid);
+
+if (!elgg_instanceof($group, 'group')) {
+ register_error(elgg_echo('groups:featured_error'));
+ forward(REFERER);
+}
+
+//get the action, is it to feature or unfeature
+if ($action == "feature") {
+ $group->featured_group = "yes";
+ system_message(elgg_echo('groups:featuredon', array($group->name)));
+} else {
+ $group->featured_group = "no";
+ system_message(elgg_echo('groups:unfeatured', array($group->name)));
+}
+
+forward(REFERER);
diff --git a/mod/groups/actions/groups/membership/add.php b/mod/groups/actions/groups/membership/add.php
new file mode 100644
index 000000000..de0cba613
--- /dev/null
+++ b/mod/groups/actions/groups/membership/add.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Add users to a group
+ *
+ * @package ElggGroups
+ */
+$logged_in_user = elgg_get_logged_in_user_entity();
+
+$user_guid = get_input('user_guid');
+if (!is_array($user_guid)) {
+ $user_guid = array($user_guid);
+}
+$group_guid = get_input('group_guid');
+$group = get_entity($group_guid);
+
+if (sizeof($user_guid)) {
+ foreach ($user_guid as $u_id) {
+ $user = get_user($u_id);
+
+ if ($user && $group && $group->canEdit()) {
+ if (!$group->isMember($user)) {
+ if (groups_join_group($group, $user)) {
+
+ // send welcome email to user
+ notify_user($user->getGUID(), $group->owner_guid,
+ elgg_echo('groups:welcome:subject', array($group->name)),
+ elgg_echo('groups:welcome:body', array(
+ $user->name,
+ $group->name,
+ $group->getURL())
+ ));
+
+ system_message(elgg_echo('groups:addedtogroup'));
+ } else {
+ // huh
+ }
+ }
+ }
+ }
+}
+
+forward(REFERER);
diff --git a/mod/groups/actions/groups/membership/delete_invite.php b/mod/groups/actions/groups/membership/delete_invite.php
new file mode 100644
index 000000000..d21aa0309
--- /dev/null
+++ b/mod/groups/actions/groups/membership/delete_invite.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Delete an invitation to join a group.
+ *
+ * @package ElggGroups
+ */
+
+$user_guid = get_input('user_guid', elgg_get_logged_in_user_guid());
+$group_guid = get_input('group_guid');
+
+$user = get_entity($user_guid);
+
+// invisible groups require overriding access to delete invite
+$old_access = elgg_set_ignore_access(true);
+$group = get_entity($group_guid);
+elgg_set_ignore_access($old_access);
+
+// If join request made
+if (check_entity_relationship($group->guid, 'invited', $user->guid)) {
+ remove_entity_relationship($group->guid, 'invited', $user->guid);
+ system_message(elgg_echo("groups:invitekilled"));
+}
+
+forward(REFERER);
diff --git a/mod/groups/actions/groups/membership/delete_request.php b/mod/groups/actions/groups/membership/delete_request.php
new file mode 100644
index 000000000..883c9d748
--- /dev/null
+++ b/mod/groups/actions/groups/membership/delete_request.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Delete a request to join a closed group.
+ *
+ * @package ElggGroups
+ */
+
+$user_guid = get_input('user_guid', elgg_get_logged_in_user_guid());
+$group_guid = get_input('group_guid');
+
+$user = get_entity($user_guid);
+$group = get_entity($group_guid);
+
+// If join request made
+if (check_entity_relationship($user->guid, 'membership_request', $group->guid)) {
+ remove_entity_relationship($user->guid, 'membership_request', $group->guid);
+ system_message(elgg_echo("groups:joinrequestkilled"));
+}
+
+forward(REFERER);
diff --git a/mod/groups/actions/groups/membership/invite.php b/mod/groups/actions/groups/membership/invite.php
new file mode 100644
index 000000000..a96165b0e
--- /dev/null
+++ b/mod/groups/actions/groups/membership/invite.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Invite users to join a group
+ *
+ * @package ElggGroups
+ */
+
+$logged_in_user = elgg_get_logged_in_user_entity();
+
+$user_guids = get_input('user_guid');
+if (!is_array($user_guids)) {
+ $user_guids = array($user_guids);
+}
+$group_guid = get_input('group_guid');
+$group = get_entity($group_guid);
+
+if (count($user_guids) > 0 && elgg_instanceof($group, 'group') && $group->canEdit()) {
+ foreach ($user_guids as $guid) {
+ $user = get_user($guid);
+ if (!$user) {
+ continue;
+ }
+
+ if (check_entity_relationship($group->guid, 'invited', $user->guid)) {
+ register_error(elgg_echo("groups:useralreadyinvited"));
+ continue;
+ }
+
+ if (check_entity_relationship($user->guid, 'member', $group->guid)) {
+ // @todo add error message
+ continue;
+ }
+
+ // Create relationship
+ add_entity_relationship($group->guid, 'invited', $user->guid);
+
+ // Send notification
+ $url = elgg_normalize_url("groups/invitations/$user->username");
+ $result = notify_user($user->getGUID(), $group->owner_guid,
+ elgg_echo('groups:invite:subject', array($user->name, $group->name)),
+ elgg_echo('groups:invite:body', array(
+ $user->name,
+ $logged_in_user->name,
+ $group->name,
+ $url,
+ )),
+ NULL);
+ if ($result) {
+ system_message(elgg_echo("groups:userinvited"));
+ } else {
+ register_error(elgg_echo("groups:usernotinvited"));
+ }
+ }
+}
+
+forward(REFERER);
diff --git a/mod/groups/actions/groups/membership/join.php b/mod/groups/actions/groups/membership/join.php
new file mode 100644
index 000000000..b4f4e280c
--- /dev/null
+++ b/mod/groups/actions/groups/membership/join.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Join a group
+ *
+ * Three states:
+ * open group so user joins
+ * closed group so request sent to group owner
+ * closed group with invite so user joins
+ *
+ * @package ElggGroups
+ */
+
+global $CONFIG;
+
+$user_guid = get_input('user_guid', elgg_get_logged_in_user_guid());
+$group_guid = get_input('group_guid');
+
+$user = get_entity($user_guid);
+
+// access bypass for getting invisible group
+$ia = elgg_set_ignore_access(true);
+$group = get_entity($group_guid);
+elgg_set_ignore_access($ia);
+
+if (($user instanceof ElggUser) && ($group instanceof ElggGroup)) {
+
+ // join or request
+ $join = false;
+ if ($group->isPublicMembership() || $group->canEdit($user->guid)) {
+ // anyone can join public groups and admins can join any group
+ $join = true;
+ } else {
+ if (check_entity_relationship($group->guid, 'invited', $user->guid)) {
+ // user has invite to closed group
+ $join = true;
+ }
+ }
+
+ if ($join) {
+ if (groups_join_group($group, $user)) {
+ system_message(elgg_echo("groups:joined"));
+ forward($group->getURL());
+ } else {
+ register_error(elgg_echo("groups:cantjoin"));
+ }
+ } else {
+ add_entity_relationship($user->guid, 'membership_request', $group->guid);
+
+ // Notify group owner
+ $url = "{$CONFIG->url}groups/requests/$group->guid";
+ $subject = elgg_echo('groups:request:subject', array(
+ $user->name,
+ $group->name,
+ ));
+ $body = elgg_echo('groups:request:body', array(
+ $group->getOwnerEntity()->name,
+ $user->name,
+ $group->name,
+ $user->getURL(),
+ $url,
+ ));
+ if (notify_user($group->owner_guid, $user->getGUID(), $subject, $body)) {
+ system_message(elgg_echo("groups:joinrequestmade"));
+ } else {
+ register_error(elgg_echo("groups:joinrequestnotmade"));
+ }
+ }
+} else {
+ register_error(elgg_echo("groups:cantjoin"));
+}
+
+forward(REFERER);
diff --git a/mod/groups/actions/groups/membership/leave.php b/mod/groups/actions/groups/membership/leave.php
new file mode 100644
index 000000000..4f34c7dde
--- /dev/null
+++ b/mod/groups/actions/groups/membership/leave.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Leave a group action.
+ *
+ * @package ElggGroups
+ */
+
+$user_guid = get_input('user_guid');
+$group_guid = get_input('group_guid');
+
+$user = NULL;
+if (!$user_guid) {
+ $user = elgg_get_logged_in_user_entity();
+} else {
+ $user = get_entity($user_guid);
+}
+
+$group = get_entity($group_guid);
+
+elgg_set_page_owner_guid($group->guid);
+
+if (($user instanceof ElggUser) && ($group instanceof ElggGroup)) {
+ if ($group->getOwnerGUID() != elgg_get_logged_in_user_guid()) {
+ if ($group->leave($user)) {
+ system_message(elgg_echo("groups:left"));
+ } else {
+ register_error(elgg_echo("groups:cantleave"));
+ }
+ } else {
+ register_error(elgg_echo("groups:cantleave"));
+ }
+} else {
+ register_error(elgg_echo("groups:cantleave"));
+}
+
+forward(REFERER);
diff --git a/mod/groups/actions/groups/membership/remove.php b/mod/groups/actions/groups/membership/remove.php
new file mode 100644
index 000000000..650d35286
--- /dev/null
+++ b/mod/groups/actions/groups/membership/remove.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Remove a user from a group
+ *
+ * @package ElggGroups
+ */
+
+$user_guid = get_input('user_guid');
+$group_guid = get_input('group_guid');
+
+$user = get_entity($user_guid);
+$group = get_entity($group_guid);
+
+elgg_set_page_owner_guid($group->guid);
+
+if (($user instanceof ElggUser) && ($group instanceof ElggGroup) && $group->canEdit()) {
+ // Don't allow removing group owner
+ if ($group->getOwnerGUID() != $user->getGUID()) {
+ if ($group->leave($user)) {
+ system_message(elgg_echo("groups:removed", array($user->name)));
+ } else {
+ register_error(elgg_echo("groups:cantremove"));
+ }
+ } else {
+ register_error(elgg_echo("groups:cantremove"));
+ }
+} else {
+ register_error(elgg_echo("groups:cantremove"));
+}
+
+forward(REFERER);
diff --git a/mod/groups/graphics/defaultlarge.gif b/mod/groups/graphics/defaultlarge.gif
new file mode 100644
index 000000000..b0921b8d8
--- /dev/null
+++ b/mod/groups/graphics/defaultlarge.gif
Binary files differ
diff --git a/mod/groups/graphics/defaultmedium.gif b/mod/groups/graphics/defaultmedium.gif
new file mode 100644
index 000000000..ae230a3d7
--- /dev/null
+++ b/mod/groups/graphics/defaultmedium.gif
Binary files differ
diff --git a/mod/groups/graphics/defaultsmall.gif b/mod/groups/graphics/defaultsmall.gif
new file mode 100644
index 000000000..81d89110d
--- /dev/null
+++ b/mod/groups/graphics/defaultsmall.gif
Binary files differ
diff --git a/mod/groups/graphics/defaulttiny.gif b/mod/groups/graphics/defaulttiny.gif
new file mode 100644
index 000000000..86dc96ae4
--- /dev/null
+++ b/mod/groups/graphics/defaulttiny.gif
Binary files differ
diff --git a/mod/groups/icon.php b/mod/groups/icon.php
new file mode 100644
index 000000000..ebdc1eb6d
--- /dev/null
+++ b/mod/groups/icon.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Icon display
+ *
+ * @package ElggGroups
+ */
+
+require_once(dirname(dirname(dirname(__FILE__))) . "/engine/start.php");
+
+$group_guid = get_input('group_guid');
+
+/* @var ElggGroup $group */
+$group = get_entity($group_guid);
+if (!($group instanceof ElggGroup)) {
+ header("HTTP/1.1 404 Not Found");
+ exit;
+}
+
+// If is the same ETag, content didn't changed.
+$etag = $group->icontime . $group_guid;
+if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) == "\"$etag\"") {
+ header("HTTP/1.1 304 Not Modified");
+ exit;
+}
+
+$size = strtolower(get_input('size'));
+if (!in_array($size, array('large', 'medium', 'small', 'tiny', 'master', 'topbar')))
+ $size = "medium";
+
+$success = false;
+
+$filehandler = new ElggFile();
+$filehandler->owner_guid = $group->owner_guid;
+$filehandler->setFilename("groups/" . $group->guid . $size . ".jpg");
+
+$success = false;
+if ($filehandler->open("read")) {
+ if ($contents = $filehandler->read($filehandler->size())) {
+ $success = true;
+ }
+}
+
+if (!$success) {
+ $location = elgg_get_plugins_path() . "groups/graphics/default{$size}.gif";
+ $contents = @file_get_contents($location);
+}
+
+header("Content-type: image/jpeg");
+header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', strtotime("+10 days")), true);
+header("Pragma: public");
+header("Cache-Control: public");
+header("Content-Length: " . strlen($contents));
+header("ETag: \"$etag\"");
+echo $contents;
diff --git a/mod/groups/languages/en.php b/mod/groups/languages/en.php
new file mode 100644
index 000000000..9e0799b3a
--- /dev/null
+++ b/mod/groups/languages/en.php
@@ -0,0 +1,299 @@
+<?php
+/**
+ * Elgg groups plugin language pack
+ *
+ * @package ElggGroups
+ */
+
+$english = array(
+
+ /**
+ * Menu items and titles
+ */
+ 'groups' => "Groups",
+ 'groups:owned' => "Groups I own",
+ 'groups:owned:user' => 'Groups %s owns',
+ 'groups:yours' => "My groups",
+ 'groups:user' => "%s's groups",
+ 'groups:all' => "All groups",
+ 'groups:add' => "Create a new group",
+ 'groups:edit' => "Edit group",
+ 'groups:delete' => 'Delete group',
+ 'groups:membershiprequests' => 'Manage join requests',
+ 'groups:membershiprequests:pending' => 'Manage join requests (%s)',
+ 'groups:invitations' => 'Group invitations',
+ 'groups:invitations:pending' => 'Group invitations (%s)',
+
+ 'groups:icon' => 'Group icon (leave blank to leave unchanged)',
+ 'groups:name' => 'Group name',
+ 'groups:username' => 'Group short name (displayed in URLs, alphanumeric characters only)',
+ 'groups:description' => 'Description',
+ 'groups:briefdescription' => 'Brief description',
+ 'groups:interests' => 'Tags',
+ 'groups:website' => 'Website',
+ 'groups:members' => 'Group members',
+ 'groups:my_status' => 'My status',
+ 'groups:my_status:group_owner' => 'You own this group',
+ 'groups:my_status:group_member' => 'You are in this group',
+ 'groups:subscribed' => 'Group notifications on',
+ 'groups:unsubscribed' => 'Group notifications off',
+
+ 'groups:members:title' => 'Members of %s',
+ 'groups:members:more' => "View all members",
+ 'groups:membership' => "Group membership permissions",
+ 'groups:access' => "Access permissions",
+ 'groups:owner' => "Owner",
+ 'groups:owner:warning' => "Warning: if you change this value, you will no longer be the owner of this group.",
+ 'groups:widget:num_display' => 'Number of groups to display',
+ 'groups:widget:membership' => 'Group membership',
+ 'groups:widgets:description' => 'Display the groups you are a member of on your profile',
+ 'groups:noaccess' => 'No access to group',
+ 'groups:permissions:error' => 'You do not have the permissions for this',
+ 'groups:ingroup' => 'in the group',
+ 'groups:cantcreate' => 'You can not create a group. Only admins can.',
+ 'groups:cantedit' => 'You can not edit this group',
+ 'groups:saved' => 'Group saved',
+ 'groups:featured' => 'Featured groups',
+ 'groups:makeunfeatured' => 'Unfeature',
+ 'groups:makefeatured' => 'Make featured',
+ 'groups:featuredon' => '%s is now a featured group.',
+ 'groups:unfeatured' => '%s has been removed from the featured groups.',
+ 'groups:featured_error' => 'Invalid group.',
+ 'groups:joinrequest' => 'Request membership',
+ 'groups:join' => 'Join group',
+ 'groups:leave' => 'Leave group',
+ 'groups:invite' => 'Invite friends',
+ 'groups:invite:title' => 'Invite friends to this group',
+ 'groups:inviteto' => "Invite friends to '%s'",
+ 'groups:nofriends' => "You have no friends left who have not been invited to this group.",
+ 'groups:nofriendsatall' => 'You have no friends to invite!',
+ 'groups:viagroups' => "via groups",
+ 'groups:group' => "Group",
+ 'groups:search:tags' => "tag",
+ 'groups:search:title' => "Search for groups tagged with '%s'",
+ 'groups:search:none' => "No matching groups were found",
+ 'groups:search_in_group' => "Search in this group",
+ 'groups:acl' => "Group: %s",
+
+ 'discussion:notification:topic:subject' => 'New group discussion post',
+ 'groups:notification' =>
+'%s added a new discussion topic to %s:
+
+%s
+%s
+
+View and reply to the discussion:
+%s
+',
+
+ 'discussion:notification:reply:body' =>
+'%s replied to the discussion topic %s in the group %s:
+
+%s
+
+View and reply to the discussion:
+%s
+',
+
+ 'groups:activity' => "Group activity",
+ 'groups:enableactivity' => 'Enable group activity',
+ 'groups:activity:none' => "There is no group activity yet",
+
+ 'groups:notfound' => "Group not found",
+ 'groups:notfound:details' => "The requested group either does not exist or you do not have access to it",
+
+ 'groups:requests:none' => 'There are no current membership requests.',
+
+ 'groups:invitations:none' => 'There are no current invitations.',
+
+ 'item:object:groupforumtopic' => "Discussion topics",
+
+ 'groupforumtopic:new' => "Add discussion post",
+
+ 'groups:count' => "groups created",
+ 'groups:open' => "open group",
+ 'groups:closed' => "closed group",
+ 'groups:member' => "members",
+ 'groups:searchtag' => "Search for groups by tag",
+
+ 'groups:more' => 'More groups',
+ 'groups:none' => 'No groups',
+
+
+ /*
+ * Access
+ */
+ 'groups:access:private' => 'Closed - Users must be invited',
+ 'groups:access:public' => 'Open - Any user may join',
+ 'groups:access:group' => 'Group members only',
+ 'groups:closedgroup' => 'This group has a closed membership.',
+ 'groups:closedgroup:request' => 'To ask to be added, click the "request membership" menu link.',
+ 'groups:visibility' => 'Who can see this group?',
+
+ /*
+ Group tools
+ */
+ 'groups:enableforum' => 'Enable group discussion',
+ 'groups:yes' => 'yes',
+ 'groups:no' => 'no',
+ 'groups:lastupdated' => 'Last updated %s by %s',
+ 'groups:lastcomment' => 'Last comment %s by %s',
+
+ /*
+ Group discussion
+ */
+ 'discussion' => 'Discussion',
+ 'discussion:add' => 'Add discussion topic',
+ 'discussion:latest' => 'Latest discussion',
+ 'discussion:group' => 'Group discussion',
+ 'discussion:none' => 'No discussion',
+ 'discussion:reply:title' => 'Reply by %s',
+
+ 'discussion:topic:created' => 'The discussion topic was created.',
+ 'discussion:topic:updated' => 'The discussion topic was updated.',
+ 'discussion:topic:deleted' => 'Discussion topic has been deleted.',
+
+ 'discussion:topic:notfound' => 'Discussion topic not found',
+ 'discussion:error:notsaved' => 'Unable to save this topic',
+ 'discussion:error:missing' => 'Both title and message are required fields',
+ 'discussion:error:permissions' => 'You do not have permissions to perform this action',
+ 'discussion:error:notdeleted' => 'Could not delete the discussion topic',
+
+ 'discussion:reply:deleted' => 'Discussion reply has been deleted.',
+ 'discussion:reply:error:notdeleted' => 'Could not delete the discussion reply',
+
+ 'reply:this' => 'Reply to this',
+
+ 'group:replies' => 'Replies',
+ 'groups:forum:created' => 'Created %s with %d comments',
+ 'groups:forum:created:single' => 'Created %s with %d reply',
+ 'groups:forum' => 'Discussion',
+ 'groups:addtopic' => 'Add a topic',
+ 'groups:forumlatest' => 'Latest discussion',
+ 'groups:latestdiscussion' => 'Latest discussion',
+ 'groups:newest' => 'Newest',
+ 'groups:popular' => 'Popular',
+ 'groupspost:success' => 'Your reply was succesfully posted',
+ 'groups:alldiscussion' => 'Latest discussion',
+ 'groups:edittopic' => 'Edit topic',
+ 'groups:topicmessage' => 'Topic message',
+ 'groups:topicstatus' => 'Topic status',
+ 'groups:reply' => 'Post a comment',
+ 'groups:topic' => 'Topic',
+ 'groups:posts' => 'Posts',
+ 'groups:lastperson' => 'Last person',
+ 'groups:when' => 'When',
+ 'grouptopic:notcreated' => 'No topics have been created.',
+ 'groups:topicopen' => 'Open',
+ 'groups:topicclosed' => 'Closed',
+ 'groups:topicresolved' => 'Resolved',
+ 'grouptopic:created' => 'Your topic was created.',
+ 'groupstopic:deleted' => 'The topic has been deleted.',
+ 'groups:topicsticky' => 'Sticky',
+ 'groups:topicisclosed' => 'This discussion is closed.',
+ 'groups:topiccloseddesc' => 'This discussion is closed and is not accepting new comments.',
+ 'grouptopic:error' => 'Your group topic could not be created. Please try again or contact a system administrator.',
+ 'groups:forumpost:edited' => "You have successfully edited the forum post.",
+ 'groups:forumpost:error' => "There was a problem editing the forum post.",
+
+
+ 'groups:privategroup' => 'This group is closed. Requesting membership.',
+ 'groups:notitle' => 'Groups must have a title',
+ 'groups:cantjoin' => 'Can not join group',
+ 'groups:cantleave' => 'Could not leave group',
+ 'groups:removeuser' => 'Remove from group',
+ 'groups:cantremove' => 'Cannot remove user from group',
+ 'groups:removed' => 'Successfully removed %s from group',
+ 'groups:addedtogroup' => 'Successfully added the user to the group',
+ 'groups:joinrequestnotmade' => 'Could not request to join group',
+ 'groups:joinrequestmade' => 'Requested to join group',
+ 'groups:joined' => 'Successfully joined group!',
+ 'groups:left' => 'Successfully left group',
+ 'groups:notowner' => 'Sorry, you are not the owner of this group.',
+ 'groups:notmember' => 'Sorry, you are not a member of this group.',
+ 'groups:alreadymember' => 'You are already a member of this group!',
+ 'groups:userinvited' => 'User has been invited.',
+ 'groups:usernotinvited' => 'User could not be invited.',
+ 'groups:useralreadyinvited' => 'User has already been invited',
+ 'groups:invite:subject' => "%s you have been invited to join %s!",
+ 'groups:updated' => "Last reply by %s %s",
+ 'groups:started' => "Started by %s",
+ 'groups:joinrequest:remove:check' => 'Are you sure you want to remove this join request?',
+ 'groups:invite:remove:check' => 'Are you sure you want to remove this invitation?',
+ 'groups:invite:body' => "Hi %s,
+
+%s invited you to join the '%s' group. Click below to view your invitations:
+
+%s",
+
+ 'groups:welcome:subject' => "Welcome to the %s group!",
+ 'groups:welcome:body' => "Hi %s!
+
+You are now a member of the '%s' group! Click below to begin posting!
+
+%s",
+
+ 'groups:request:subject' => "%s has requested to join %s",
+ 'groups:request:body' => "Hi %s,
+
+%s has requested to join the '%s' group. Click below to view their profile:
+
+%s
+
+or click below to view the group's join requests:
+
+%s",
+
+ /*
+ Forum river items
+ */
+
+ 'river:create:group:default' => '%s created the group %s',
+ 'river:join:group:default' => '%s joined the group %s',
+ 'river:create:object:groupforumtopic' => '%s added a new discussion topic %s',
+ 'river:reply:object:groupforumtopic' => '%s replied on the discussion topic %s',
+
+ 'groups:nowidgets' => 'No widgets have been defined for this group.',
+
+
+ 'groups:widgets:members:title' => 'Group members',
+ 'groups:widgets:members:description' => 'List the members of a group.',
+ 'groups:widgets:members:label:displaynum' => 'List the members of a group.',
+ 'groups:widgets:members:label:pleaseedit' => 'Please configure this widget.',
+
+ 'groups:widgets:entities:title' => "Objects in group",
+ 'groups:widgets:entities:description' => "List the objects saved in this group",
+ 'groups:widgets:entities:label:displaynum' => 'List the objects of a group.',
+ 'groups:widgets:entities:label:pleaseedit' => 'Please configure this widget.',
+
+ 'groups:forumtopic:edited' => 'Forum topic successfully edited.',
+
+ 'groups:allowhiddengroups' => 'Do you want to allow private (invisible) groups?',
+ 'groups:whocancreate' => 'Who can create new groups?',
+
+ /**
+ * Action messages
+ */
+ 'group:deleted' => 'Group and group contents deleted',
+ 'group:notdeleted' => 'Group could not be deleted',
+
+ 'group:notfound' => 'Could not find the group',
+ 'grouppost:deleted' => 'Group posting successfully deleted',
+ 'grouppost:notdeleted' => 'Group posting could not be deleted',
+ 'groupstopic:deleted' => 'Topic deleted',
+ 'groupstopic:notdeleted' => 'Topic not deleted',
+ 'grouptopic:blank' => 'No topic',
+ 'grouptopic:notfound' => 'Could not find the topic',
+ 'grouppost:nopost' => 'Empty post',
+ 'groups:deletewarning' => "Are you sure you want to delete this group? There is no undo!",
+
+ 'groups:invitekilled' => 'The invite has been deleted.',
+ 'groups:joinrequestkilled' => 'The join request has been deleted.',
+
+ // ecml
+ 'groups:ecml:discussion' => 'Group Discussions',
+ 'groups:ecml:groupprofile' => 'Group profiles',
+
+);
+
+add_translation("en", $english);
diff --git a/mod/groups/lib/discussion.php b/mod/groups/lib/discussion.php
new file mode 100644
index 000000000..874e21b2d
--- /dev/null
+++ b/mod/groups/lib/discussion.php
@@ -0,0 +1,235 @@
+<?php
+/**
+ * Discussion function library
+ */
+
+/**
+ * List all discussion topics
+ */
+function discussion_handle_all_page() {
+
+ elgg_pop_breadcrumb();
+ elgg_push_breadcrumb(elgg_echo('discussion'));
+
+ $content = elgg_list_entities(array(
+ 'type' => 'object',
+ 'subtype' => 'groupforumtopic',
+ 'order_by' => 'e.last_action desc',
+ 'limit' => 20,
+ 'full_view' => false,
+ ));
+
+ $params = array(
+ 'content' => $content,
+ 'title' => elgg_echo('discussion:latest'),
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * List discussion topics in a group
+ *
+ * @param int $guid Group entity GUID
+ */
+function discussion_handle_list_page($guid) {
+
+ elgg_set_page_owner_guid($guid);
+
+ $group = get_entity($guid);
+ if (!elgg_instanceof($group, 'group')) {
+ forward('', '404');
+ }
+ elgg_push_breadcrumb($group->name);
+
+ elgg_register_title_button();
+
+ group_gatekeeper();
+
+ $title = elgg_echo('item:object:groupforumtopic');
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'groupforumtopic',
+ 'limit' => 20,
+ 'order_by' => 'e.last_action desc',
+ 'container_guid' => $guid,
+ 'full_view' => false,
+ );
+ $content = elgg_list_entities($options);
+ if (!$content) {
+ $content = elgg_echo('discussion:none');
+ }
+
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * Edit or add a discussion topic
+ *
+ * @param string $type 'add' or 'edit'
+ * @param int $guid GUID of group or topic
+ */
+function discussion_handle_edit_page($type, $guid) {
+ gatekeeper();
+
+ if ($type == 'add') {
+ $group = get_entity($guid);
+ if (!$group) {
+ register_error(elgg_echo('group:notfound'));
+ forward();
+ }
+
+ // make sure user has permissions to add a topic to container
+ if (!$group->canWriteToContainer(0, 'object', 'groupforumtopic')) {
+ register_error(elgg_echo('groups:permissions:error'));
+ forward($group->getURL());
+ }
+
+ $title = elgg_echo('groups:addtopic');
+
+ elgg_push_breadcrumb($group->name, "discussion/owner/$group->guid");
+ elgg_push_breadcrumb($title);
+
+ $body_vars = discussion_prepare_form_vars();
+ $content = elgg_view_form('discussion/save', array(), $body_vars);
+ } else {
+ $topic = get_entity($guid);
+ if (!$topic || !$topic->canEdit()) {
+ register_error(elgg_echo('discussion:topic:notfound'));
+ forward();
+ }
+ $group = $topic->getContainerEntity();
+ if (!$group) {
+ register_error(elgg_echo('group:notfound'));
+ forward();
+ }
+
+ $title = elgg_echo('groups:edittopic');
+
+ elgg_push_breadcrumb($group->name, "discussion/owner/$group->guid");
+ elgg_push_breadcrumb($topic->title, $topic->getURL());
+ elgg_push_breadcrumb($title);
+
+ $body_vars = discussion_prepare_form_vars($topic);
+ $content = elgg_view_form('discussion/save', array(), $body_vars);
+ }
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * View a discussion topic
+ *
+ * @param int $guid GUID of topic
+ */
+function discussion_handle_view_page($guid) {
+ // We now have RSS on topics
+ global $autofeed;
+ $autofeed = true;
+
+ $topic = get_entity($guid);
+ if (!$topic) {
+ register_error(elgg_echo('noaccess'));
+ $_SESSION['last_forward_from'] = current_page_url();
+ forward('');
+ }
+
+ $group = $topic->getContainerEntity();
+ if (!$group) {
+ register_error(elgg_echo('group:notfound'));
+ forward();
+ }
+
+ elgg_set_page_owner_guid($group->getGUID());
+
+ group_gatekeeper();
+
+ elgg_push_breadcrumb($group->name, "discussion/owner/$group->guid");
+ elgg_push_breadcrumb($topic->title);
+
+ $content = elgg_view_entity($topic, array('full_view' => true));
+ if ($topic->status == 'closed') {
+ $content .= elgg_view('discussion/replies', array(
+ 'entity' => $topic,
+ 'show_add_form' => false,
+ ));
+ $content .= elgg_view('discussion/closed');
+ } elseif ($group->canWriteToContainer(0, 'object', 'groupforumtopic') || elgg_is_admin_logged_in()) {
+ $content .= elgg_view('discussion/replies', array(
+ 'entity' => $topic,
+ 'show_add_form' => true,
+ ));
+ } else {
+ $content .= elgg_view('discussion/replies', array(
+ 'entity' => $topic,
+ 'show_add_form' => false,
+ ));
+ }
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $topic->title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($topic->title, $body);
+}
+
+/**
+ * Prepare discussion topic form variables
+ *
+ * @param ElggObject $topic Topic object if editing
+ * @return array
+ */
+function discussion_prepare_form_vars($topic = NULL) {
+ // input names => defaults
+ $values = array(
+ 'title' => '',
+ 'description' => '',
+ 'status' => '',
+ 'access_id' => ACCESS_DEFAULT,
+ 'tags' => '',
+ 'container_guid' => elgg_get_page_owner_guid(),
+ 'guid' => null,
+ 'entity' => $topic,
+ );
+
+ if ($topic) {
+ foreach (array_keys($values) as $field) {
+ if (isset($topic->$field)) {
+ $values[$field] = $topic->$field;
+ }
+ }
+ }
+
+ if (elgg_is_sticky_form('topic')) {
+ $sticky_values = elgg_get_sticky_values('topic');
+ foreach ($sticky_values as $key => $value) {
+ $values[$key] = $value;
+ }
+ }
+
+ elgg_clear_sticky_form('topic');
+
+ return $values;
+}
diff --git a/mod/groups/lib/groups.php b/mod/groups/lib/groups.php
new file mode 100644
index 000000000..d5bec1862
--- /dev/null
+++ b/mod/groups/lib/groups.php
@@ -0,0 +1,590 @@
+<?php
+/**
+ * Groups function library
+ */
+
+/**
+ * List all groups
+ */
+function groups_handle_all_page() {
+
+ // all groups doesn't get link to self
+ elgg_pop_breadcrumb();
+ elgg_push_breadcrumb(elgg_echo('groups'));
+
+ if (elgg_get_plugin_setting('limited_groups', 'groups') != 'yes' || elgg_is_admin_logged_in()) {
+ elgg_register_title_button();
+ }
+
+ $selected_tab = get_input('filter', 'newest');
+
+ switch ($selected_tab) {
+ case 'popular':
+ $content = elgg_list_entities_from_relationship_count(array(
+ 'type' => 'group',
+ 'relationship' => 'member',
+ 'inverse_relationship' => false,
+ 'full_view' => false,
+ ));
+ if (!$content) {
+ $content = elgg_echo('groups:none');
+ }
+ break;
+ case 'discussion':
+ $content = elgg_list_entities(array(
+ 'type' => 'object',
+ 'subtype' => 'groupforumtopic',
+ 'order_by' => 'e.last_action desc',
+ 'limit' => 40,
+ 'full_view' => false,
+ ));
+ if (!$content) {
+ $content = elgg_echo('discussion:none');
+ }
+ break;
+ case 'newest':
+ default:
+ $content = elgg_list_entities(array(
+ 'type' => 'group',
+ 'full_view' => false,
+ ));
+ if (!$content) {
+ $content = elgg_echo('groups:none');
+ }
+ break;
+ }
+
+ $filter = elgg_view('groups/group_sort_menu', array('selected' => $selected_tab));
+
+ $sidebar = elgg_view('groups/sidebar/find');
+ $sidebar .= elgg_view('groups/sidebar/featured');
+
+ $params = array(
+ 'content' => $content,
+ 'sidebar' => $sidebar,
+ 'filter' => $filter,
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page(elgg_echo('groups:all'), $body);
+}
+
+function groups_search_page() {
+ elgg_push_breadcrumb(elgg_echo('search'));
+
+ $tag = get_input("tag");
+ $display_query = _elgg_get_display_query($tag);
+ $title = elgg_echo('groups:search:title', array($display_query));
+
+ // groups plugin saves tags as "interests" - see groups_fields_setup() in start.php
+ $params = array(
+ 'metadata_name' => 'interests',
+ 'metadata_value' => $tag,
+ 'type' => 'group',
+ 'full_view' => FALSE,
+ );
+ $content = elgg_list_entities_from_metadata($params);
+ if (!$content) {
+ $content = elgg_echo('groups:search:none');
+ }
+
+ $sidebar = elgg_view('groups/sidebar/find');
+ $sidebar .= elgg_view('groups/sidebar/featured');
+
+ $params = array(
+ 'content' => $content,
+ 'sidebar' => $sidebar,
+ 'filter' => false,
+ 'title' => $title,
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * List owned groups
+ */
+function groups_handle_owned_page() {
+
+ $page_owner = elgg_get_page_owner_entity();
+
+ if ($page_owner->guid == elgg_get_logged_in_user_guid()) {
+ $title = elgg_echo('groups:owned');
+ } else {
+ $title = elgg_echo('groups:owned:user', array($page_owner->name));
+ }
+ elgg_push_breadcrumb($title);
+
+ if (elgg_get_plugin_setting('limited_groups', 'groups') != 'yes' || elgg_is_admin_logged_in()) {
+ elgg_register_title_button();
+ }
+
+ $content = elgg_list_entities(array(
+ 'type' => 'group',
+ 'owner_guid' => elgg_get_page_owner_guid(),
+ 'full_view' => false,
+ ));
+ if (!$content) {
+ $content = elgg_echo('groups:none');
+ }
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * List groups the user is memober of
+ */
+function groups_handle_mine_page() {
+
+ $page_owner = elgg_get_page_owner_entity();
+
+ if ($page_owner->guid == elgg_get_logged_in_user_guid()) {
+ $title = elgg_echo('groups:yours');
+ } else {
+ $title = elgg_echo('groups:user', array($page_owner->name));
+ }
+ elgg_push_breadcrumb($title);
+
+ if (elgg_get_plugin_setting('limited_groups', 'groups') != 'yes' || elgg_is_admin_logged_in()) {
+ elgg_register_title_button();
+ }
+
+ $content = elgg_list_entities_from_relationship(array(
+ 'type' => 'group',
+ 'relationship' => 'member',
+ 'relationship_guid' => elgg_get_page_owner_guid(),
+ 'inverse_relationship' => false,
+ 'full_view' => false,
+ ));
+ if (!$content) {
+ $content = elgg_echo('groups:none');
+ }
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * Create or edit a group
+ *
+ * @param string $page
+ * @param int $guid
+ */
+function groups_handle_edit_page($page, $guid = 0) {
+ gatekeeper();
+
+ if ($page == 'add') {
+ elgg_set_page_owner_guid(elgg_get_logged_in_user_guid());
+ $title = elgg_echo('groups:add');
+ elgg_push_breadcrumb($title);
+ if (elgg_get_plugin_setting('limited_groups', 'groups') != 'yes' || elgg_is_admin_logged_in()) {
+ $content = elgg_view('groups/edit');
+ } else {
+ $content = elgg_echo('groups:cantcreate');
+ }
+ } else {
+ $title = elgg_echo("groups:edit");
+ $group = get_entity($guid);
+
+ if ($group && $group->canEdit()) {
+ elgg_set_page_owner_guid($group->getGUID());
+ elgg_push_breadcrumb($group->name, $group->getURL());
+ elgg_push_breadcrumb($title);
+ $content = elgg_view("groups/edit", array('entity' => $group));
+ } else {
+ $content = elgg_echo('groups:noaccess');
+ }
+ }
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * Group invitations for a user
+ */
+function groups_handle_invitations_page() {
+ gatekeeper();
+
+ $user = elgg_get_page_owner_entity();
+
+ $title = elgg_echo('groups:invitations');
+ elgg_push_breadcrumb($title);
+
+ // @todo temporary workaround for exts #287.
+ $invitations = groups_get_invited_groups(elgg_get_logged_in_user_guid());
+ $content = elgg_view('groups/invitationrequests', array('invitations' => $invitations));
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * Group profile page
+ *
+ * @param int $guid Group entity GUID
+ */
+function groups_handle_profile_page($guid) {
+ elgg_set_page_owner_guid($guid);
+
+ // turn this into a core function
+ global $autofeed;
+ $autofeed = true;
+
+ elgg_push_context('group_profile');
+
+ $group = get_entity($guid);
+ if (!elgg_instanceof($group, 'group')) {
+ forward('', '404');
+ }
+
+ elgg_push_breadcrumb($group->name);
+
+ groups_register_profile_buttons($group);
+
+ $content = elgg_view('groups/profile/layout', array('entity' => $group));
+ $sidebar = '';
+
+ if (group_gatekeeper(false)) {
+ if (elgg_is_active_plugin('search')) {
+ $sidebar .= elgg_view('groups/sidebar/search', array('entity' => $group));
+ }
+ $sidebar .= elgg_view('groups/sidebar/members', array('entity' => $group));
+
+ $subscribed = false;
+ if (elgg_is_active_plugin('notifications')) {
+ global $NOTIFICATION_HANDLERS;
+
+ foreach ($NOTIFICATION_HANDLERS as $method => $foo) {
+ $relationship = check_entity_relationship(elgg_get_logged_in_user_guid(),
+ 'notify' . $method, $guid);
+
+ if ($relationship) {
+ $subscribed = true;
+ break;
+ }
+ }
+ }
+
+ $sidebar .= elgg_view('groups/sidebar/my_status', array(
+ 'entity' => $group,
+ 'subscribed' => $subscribed
+ ));
+ }
+
+ $params = array(
+ 'content' => $content,
+ 'sidebar' => $sidebar,
+ 'title' => $group->name,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($group->name, $body);
+}
+
+/**
+ * Group activity page
+ *
+ * @param int $guid Group entity GUID
+ */
+function groups_handle_activity_page($guid) {
+
+ elgg_set_page_owner_guid($guid);
+
+ $group = get_entity($guid);
+ if (!$group || !elgg_instanceof($group, 'group')) {
+ forward();
+ }
+
+ group_gatekeeper();
+
+ $title = elgg_echo('groups:activity');
+
+ elgg_push_breadcrumb($group->name, $group->getURL());
+ elgg_push_breadcrumb($title);
+
+ $db_prefix = elgg_get_config('dbprefix');
+
+ $content = elgg_list_river(array(
+ 'joins' => array("JOIN {$db_prefix}entities e ON e.guid = rv.object_guid"),
+ 'wheres' => array("e.container_guid = $guid")
+ ));
+ if (!$content) {
+ $content = '<p>' . elgg_echo('groups:activity:none') . '</p>';
+ }
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * Group members page
+ *
+ * @param int $guid Group entity GUID
+ */
+function groups_handle_members_page($guid) {
+
+ elgg_set_page_owner_guid($guid);
+
+ $group = get_entity($guid);
+ if (!$group || !elgg_instanceof($group, 'group')) {
+ forward();
+ }
+
+ group_gatekeeper();
+
+ $title = elgg_echo('groups:members:title', array($group->name));
+
+ elgg_push_breadcrumb($group->name, $group->getURL());
+ elgg_push_breadcrumb(elgg_echo('groups:members'));
+
+ $db_prefix = elgg_get_config('dbprefix');
+ $content = elgg_list_entities_from_relationship(array(
+ 'relationship' => 'member',
+ 'relationship_guid' => $group->guid,
+ 'inverse_relationship' => true,
+ 'type' => 'user',
+ 'limit' => 20,
+ 'joins' => array("JOIN {$db_prefix}users_entity u ON e.guid=u.guid"),
+ 'order_by' => 'u.name ASC',
+ ));
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * Invite users to a group
+ *
+ * @param int $guid Group entity GUID
+ */
+function groups_handle_invite_page($guid) {
+ gatekeeper();
+
+ elgg_set_page_owner_guid($guid);
+
+ $group = get_entity($guid);
+
+ $title = elgg_echo('groups:invite:title');
+
+ elgg_push_breadcrumb($group->name, $group->getURL());
+ elgg_push_breadcrumb(elgg_echo('groups:invite'));
+
+ if ($group && $group->canEdit()) {
+ $content = elgg_view_form('groups/invite', array(
+ 'id' => 'invite_to_group',
+ 'class' => 'elgg-form-alt mtm',
+ ), array(
+ 'entity' => $group,
+ ));
+ } else {
+ $content .= elgg_echo('groups:noaccess');
+ }
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * Manage requests to join a group
+ *
+ * @param int $guid Group entity GUID
+ */
+function groups_handle_requests_page($guid) {
+
+ gatekeeper();
+
+ elgg_set_page_owner_guid($guid);
+
+ $group = get_entity($guid);
+
+ $title = elgg_echo('groups:membershiprequests');
+
+ if ($group && $group->canEdit()) {
+ elgg_push_breadcrumb($group->name, $group->getURL());
+ elgg_push_breadcrumb($title);
+
+ $requests = elgg_get_entities_from_relationship(array(
+ 'type' => 'user',
+ 'relationship' => 'membership_request',
+ 'relationship_guid' => $guid,
+ 'inverse_relationship' => true,
+ 'limit' => 0,
+ ));
+ $content = elgg_view('groups/membershiprequests', array(
+ 'requests' => $requests,
+ 'entity' => $group,
+ ));
+
+ } else {
+ $content = elgg_echo("groups:noaccess");
+ }
+
+ $params = array(
+ 'content' => $content,
+ 'title' => $title,
+ 'filter' => '',
+ );
+ $body = elgg_view_layout('content', $params);
+
+ echo elgg_view_page($title, $body);
+}
+
+/**
+ * Registers the buttons for title area of the group profile page
+ *
+ * @param ElggGroup $group
+ */
+function groups_register_profile_buttons($group) {
+
+ $actions = array();
+
+ // group owners
+ if ($group->canEdit()) {
+ // edit and invite
+ $url = elgg_get_site_url() . "groups/edit/{$group->getGUID()}";
+ $actions[$url] = 'groups:edit';
+ $url = elgg_get_site_url() . "groups/invite/{$group->getGUID()}";
+ $actions[$url] = 'groups:invite';
+ }
+
+ // group members
+ if ($group->isMember(elgg_get_logged_in_user_entity())) {
+ if ($group->getOwnerGUID() != elgg_get_logged_in_user_guid()) {
+ // leave
+ $url = elgg_get_site_url() . "action/groups/leave?group_guid={$group->getGUID()}";
+ $url = elgg_add_action_tokens_to_url($url);
+ $actions[$url] = 'groups:leave';
+ }
+ } elseif (elgg_is_logged_in()) {
+ // join - admins can always join.
+ $url = elgg_get_site_url() . "action/groups/join?group_guid={$group->getGUID()}";
+ $url = elgg_add_action_tokens_to_url($url);
+ if ($group->isPublicMembership() || $group->canEdit()) {
+ $actions[$url] = 'groups:join';
+ } else {
+ // request membership
+ $actions[$url] = 'groups:joinrequest';
+ }
+ }
+
+ if ($actions) {
+ foreach ($actions as $url => $text) {
+ elgg_register_menu_item('title', array(
+ 'name' => $text,
+ 'href' => $url,
+ 'text' => elgg_echo($text),
+ 'link_class' => 'elgg-button elgg-button-action',
+ ));
+ }
+ }
+}
+
+/**
+ * Prepares variables for the group edit form view.
+ *
+ * @param mixed $group ElggGroup or null. If a group, uses values from the group.
+ * @return array
+ */
+function groups_prepare_form_vars($group = null) {
+ $values = array(
+ 'name' => '',
+ 'membership' => ACCESS_PUBLIC,
+ 'vis' => ACCESS_PUBLIC,
+ 'guid' => null,
+ 'entity' => null
+ );
+
+ // handle customizable profile fields
+ $fields = elgg_get_config('group');
+
+ if ($fields) {
+ foreach ($fields as $name => $type) {
+ $values[$name] = '';
+ }
+ }
+
+ // handle tool options
+ $tools = elgg_get_config('group_tool_options');
+ if ($tools) {
+ foreach ($tools as $group_option) {
+ $option_name = $group_option->name . "_enable";
+ $values[$option_name] = $group_option->default_on ? 'yes' : 'no';
+ }
+ }
+
+ // get current group settings
+ if ($group) {
+ foreach (array_keys($values) as $field) {
+ if (isset($group->$field)) {
+ $values[$field] = $group->$field;
+ }
+ }
+
+ if ($group->access_id != ACCESS_PUBLIC && $group->access_id != ACCESS_LOGGED_IN) {
+ // group only access - this is done to handle access not created when group is created
+ $values['vis'] = ACCESS_PRIVATE;
+ } else {
+ $values['vis'] = $group->access_id;
+ }
+
+ $values['entity'] = $group;
+ }
+
+ // get any sticky form settings
+ if (elgg_is_sticky_form('groups')) {
+ $sticky_values = elgg_get_sticky_values('groups');
+ foreach ($sticky_values as $key => $value) {
+ $values[$key] = $value;
+ }
+ }
+
+ elgg_clear_sticky_form('groups');
+
+ return $values;
+}
diff --git a/mod/groups/manifest.xml b/mod/groups/manifest.xml
new file mode 100644
index 000000000..fd28360d0
--- /dev/null
+++ b/mod/groups/manifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin_manifest xmlns="http://www.elgg.org/plugin_manifest/1.8">
+ <name>Groups</name>
+ <author>Core developers</author>
+ <version>1.8</version>
+ <category>bundled</category>
+ <category>social</category>
+ <category>widget</category>
+ <description>Provides group support for elgg</description>
+ <website>http://www.elgg.org/</website>
+ <copyright>See COPYRIGHT.txt</copyright>
+ <license>GNU General Public License version 2</license>
+ <requires>
+ <type>elgg_release</type>
+ <version>1.8</version>
+ </requires>
+ <activate_on_install>true</activate_on_install>
+</plugin_manifest>
diff --git a/mod/groups/start.php b/mod/groups/start.php
new file mode 100644
index 000000000..6002a535c
--- /dev/null
+++ b/mod/groups/start.php
@@ -0,0 +1,1073 @@
+<?php
+/**
+ * Elgg groups plugin
+ *
+ * @package ElggGroups
+ */
+
+elgg_register_event_handler('init', 'system', 'groups_init');
+
+// Ensure this runs after other plugins
+elgg_register_event_handler('init', 'system', 'groups_fields_setup', 10000);
+
+/**
+ * Initialize the groups plugin.
+ */
+function groups_init() {
+
+ elgg_register_library('elgg:groups', elgg_get_plugins_path() . 'groups/lib/groups.php');
+
+ // register group entities for search
+ elgg_register_entity_type('group', '');
+
+ // Set up the menu
+ $item = new ElggMenuItem('groups', elgg_echo('groups'), 'groups/all');
+ elgg_register_menu_item('site', $item);
+
+ // Register a page handler, so we can have nice URLs
+ elgg_register_page_handler('groups', 'groups_page_handler');
+
+ // Register URL handlers for groups
+ elgg_register_entity_url_handler('group', 'all', 'groups_url');
+ elgg_register_plugin_hook_handler('entity:icon:url', 'group', 'groups_icon_url_override');
+
+ // Register an icon handler for groups
+ elgg_register_page_handler('groupicon', 'groups_icon_handler');
+
+ // Register some actions
+ $action_base = elgg_get_plugins_path() . 'groups/actions/groups';
+ elgg_register_action("groups/edit", "$action_base/edit.php");
+ elgg_register_action("groups/delete", "$action_base/delete.php");
+ elgg_register_action("groups/featured", "$action_base/featured.php", 'admin');
+
+ $action_base .= '/membership';
+ elgg_register_action("groups/invite", "$action_base/invite.php");
+ elgg_register_action("groups/join", "$action_base/join.php");
+ elgg_register_action("groups/leave", "$action_base/leave.php");
+ elgg_register_action("groups/remove", "$action_base/remove.php");
+ elgg_register_action("groups/killrequest", "$action_base/delete_request.php");
+ elgg_register_action("groups/killinvitation", "$action_base/delete_invite.php");
+ elgg_register_action("groups/addtogroup", "$action_base/add.php");
+
+ // Add some widgets
+ elgg_register_widget_type('a_users_groups', elgg_echo('groups:widget:membership'), elgg_echo('groups:widgets:description'));
+
+ // add group activity tool option
+ add_group_tool_option('activity', elgg_echo('groups:enableactivity'), true);
+ elgg_extend_view('groups/tool_latest', 'groups/profile/activity_module');
+
+ // add link to owner block
+ elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'groups_activity_owner_block_menu');
+
+ // group entity menu
+ elgg_register_plugin_hook_handler('register', 'menu:entity', 'groups_entity_menu_setup');
+
+ // group user hover menu
+ elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'groups_user_entity_menu_setup');
+
+ // delete and edit annotations for topic replies
+ elgg_register_plugin_hook_handler('register', 'menu:annotation', 'groups_annotation_menu_setup');
+
+ //extend some views
+ elgg_extend_view('css/elgg', 'groups/css');
+ elgg_extend_view('js/elgg', 'groups/js');
+
+ // Access permissions
+ elgg_register_plugin_hook_handler('access:collections:write', 'all', 'groups_write_acl_plugin_hook');
+ //elgg_register_plugin_hook_handler('access:collections:read', 'all', 'groups_read_acl_plugin_hook');
+
+ // Register profile menu hook
+ elgg_register_plugin_hook_handler('profile_menu', 'profile', 'forum_profile_menu');
+ elgg_register_plugin_hook_handler('profile_menu', 'profile', 'activity_profile_menu');
+
+ // allow ecml in discussion and profiles
+ elgg_register_plugin_hook_handler('get_views', 'ecml', 'groups_ecml_views_hook');
+ elgg_register_plugin_hook_handler('get_views', 'ecml', 'groupprofile_ecml_views_hook');
+
+ // Register a handler for create groups
+ elgg_register_event_handler('create', 'group', 'groups_create_event_listener');
+
+ // Register a handler for delete groups
+ elgg_register_event_handler('delete', 'group', 'groups_delete_event_listener');
+
+ elgg_register_event_handler('join', 'group', 'groups_user_join_event_listener');
+ elgg_register_event_handler('leave', 'group', 'groups_user_leave_event_listener');
+ elgg_register_event_handler('pagesetup', 'system', 'groups_setup_sidebar_menus');
+
+ elgg_register_plugin_hook_handler('access:collections:add_user', 'collection', 'groups_access_collection_override');
+
+ elgg_register_event_handler('upgrade', 'system', 'groups_run_upgrades');
+}
+
+/**
+ * This function loads a set of default fields into the profile, then triggers
+ * a hook letting other plugins to edit add and delete fields.
+ *
+ * Note: This is a system:init event triggered function and is run at a super
+ * low priority to guarantee that it is called after all other plugins have
+ * initialized.
+ */
+function groups_fields_setup() {
+
+ $profile_defaults = array(
+ 'description' => 'longtext',
+ 'briefdescription' => 'text',
+ 'interests' => 'tags',
+ //'website' => 'url',
+ );
+
+ $profile_defaults = elgg_trigger_plugin_hook('profile:fields', 'group', NULL, $profile_defaults);
+
+ elgg_set_config('group', $profile_defaults);
+
+ // register any tag metadata names
+ foreach ($profile_defaults as $name => $type) {
+ if ($type == 'tags') {
+ elgg_register_tag_metadata_name($name);
+
+ // only shows up in search but why not just set this in en.php as doing it here
+ // means you cannot override it in a plugin
+ add_translation(get_current_language(), array("tag_names:$name" => elgg_echo("groups:$name")));
+ }
+ }
+}
+
+/**
+ * Configure the groups sidebar menu. Triggered on page setup
+ *
+ */
+function groups_setup_sidebar_menus() {
+
+ // Get the page owner entity
+ $page_owner = elgg_get_page_owner_entity();
+
+ if (elgg_in_context('group_profile')) {
+ if (!elgg_instanceof($page_owner, 'group')) {
+ forward('', '404');
+ }
+
+ if (elgg_is_logged_in() && $page_owner->canEdit() && !$page_owner->isPublicMembership()) {
+ $url = elgg_get_site_url() . "groups/requests/{$page_owner->getGUID()}";
+
+ $count = elgg_get_entities_from_relationship(array(
+ 'type' => 'user',
+ 'relationship' => 'membership_request',
+ 'relationship_guid' => $page_owner->getGUID(),
+ 'inverse_relationship' => true,
+ 'count' => true,
+ ));
+
+ if ($count) {
+ $text = elgg_echo('groups:membershiprequests:pending', array($count));
+ } else {
+ $text = elgg_echo('groups:membershiprequests');
+ }
+
+ elgg_register_menu_item('page', array(
+ 'name' => 'membership_requests',
+ 'text' => $text,
+ 'href' => $url,
+ ));
+ }
+ }
+ if (elgg_get_context() == 'groups' && !elgg_instanceof($page_owner, 'group')) {
+ elgg_register_menu_item('page', array(
+ 'name' => 'groups:all',
+ 'text' => elgg_echo('groups:all'),
+ 'href' => 'groups/all',
+ ));
+
+ $user = elgg_get_logged_in_user_entity();
+ if ($user) {
+ $url = "groups/owner/$user->username";
+ $item = new ElggMenuItem('groups:owned', elgg_echo('groups:owned'), $url);
+ elgg_register_menu_item('page', $item);
+
+ $url = "groups/member/$user->username";
+ $item = new ElggMenuItem('groups:member', elgg_echo('groups:yours'), $url);
+ elgg_register_menu_item('page', $item);
+
+ $url = "groups/invitations/$user->username";
+ $invitations = groups_get_invited_groups($user->getGUID());
+ if (is_array($invitations) && !empty($invitations)) {
+ $invitation_count = count($invitations);
+ $text = elgg_echo('groups:invitations:pending', array($invitation_count));
+ } else {
+ $text = elgg_echo('groups:invitations');
+ }
+
+ $item = new ElggMenuItem('groups:user:invites', $text, $url);
+ elgg_register_menu_item('page', $item);
+ }
+ }
+}
+
+/**
+ * Groups page handler
+ *
+ * URLs take the form of
+ * All groups: groups/all
+ * User's owned groups: groups/owner/<username>
+ * User's member groups: groups/member/<username>
+ * Group profile: groups/profile/<guid>/<title>
+ * New group: groups/add/<guid>
+ * Edit group: groups/edit/<guid>
+ * Group invitations: groups/invitations/<username>
+ * Invite to group: groups/invite/<guid>
+ * Membership requests: groups/requests/<guid>
+ * Group activity: groups/activity/<guid>
+ * Group members: groups/members/<guid>
+ *
+ * @param array $page Array of url segments for routing
+ * @return bool
+ */
+function groups_page_handler($page) {
+
+ // forward old profile urls
+ if (is_numeric($page[0])) {
+ $group = get_entity($page[0]);
+ if (elgg_instanceof($group, 'group', '', 'ElggGroup')) {
+ system_message(elgg_echo('changebookmark'));
+ forward($group->getURL());
+ }
+ }
+
+ elgg_load_library('elgg:groups');
+
+ if (!isset($page[0])) {
+ $page[0] = 'all';
+ }
+
+ elgg_push_breadcrumb(elgg_echo('groups'), "groups/all");
+
+ switch ($page[0]) {
+ case 'all':
+ groups_handle_all_page();
+ break;
+ case 'search':
+ groups_search_page();
+ break;
+ case 'owner':
+ groups_handle_owned_page();
+ break;
+ case 'member':
+ set_input('username', $page[1]);
+ groups_handle_mine_page();
+ break;
+ case 'invitations':
+ set_input('username', $page[1]);
+ groups_handle_invitations_page();
+ break;
+ case 'add':
+ groups_handle_edit_page('add');
+ break;
+ case 'edit':
+ groups_handle_edit_page('edit', $page[1]);
+ break;
+ case 'profile':
+ groups_handle_profile_page($page[1]);
+ break;
+ case 'activity':
+ groups_handle_activity_page($page[1]);
+ break;
+ case 'members':
+ groups_handle_members_page($page[1]);
+ break;
+ case 'invite':
+ groups_handle_invite_page($page[1]);
+ break;
+ case 'requests':
+ groups_handle_requests_page($page[1]);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Handle group icons.
+ *
+ * @param array $page
+ * @return void
+ */
+function groups_icon_handler($page) {
+
+ // The username should be the file we're getting
+ if (isset($page[0])) {
+ set_input('group_guid', $page[0]);
+ }
+ if (isset($page[1])) {
+ set_input('size', $page[1]);
+ }
+ // Include the standard profile index
+ $plugin_dir = elgg_get_plugins_path();
+ include("$plugin_dir/groups/icon.php");
+ return true;
+}
+
+/**
+ * Populates the ->getUrl() method for group objects
+ *
+ * @param ElggEntity $entity File entity
+ * @return string File URL
+ */
+function groups_url($entity) {
+ $title = elgg_get_friendly_title($entity->name);
+
+ return "groups/profile/{$entity->guid}/$title";
+}
+
+/**
+ * Override the default entity icon for groups
+ *
+ * @return string Relative URL
+ */
+function groups_icon_url_override($hook, $type, $returnvalue, $params) {
+ /* @var ElggGroup $group */
+ $group = $params['entity'];
+ $size = $params['size'];
+
+ $icontime = $group->icontime;
+ // handle missing metadata (pre 1.7 installations)
+ if (null === $icontime) {
+ $file = new ElggFile();
+ $file->owner_guid = $group->owner_guid;
+ $file->setFilename("groups/" . $group->guid . "large.jpg");
+ $icontime = $file->exists() ? time() : 0;
+ create_metadata($group->guid, 'icontime', $icontime, 'integer', $group->owner_guid, ACCESS_PUBLIC);
+ }
+ if ($icontime) {
+ // return thumbnail
+ return "groupicon/$group->guid/$size/$icontime.jpg";
+ }
+
+ return "mod/groups/graphics/default{$size}.gif";
+}
+
+/**
+ * Add owner block link
+ */
+function groups_activity_owner_block_menu($hook, $type, $return, $params) {
+ if (elgg_instanceof($params['entity'], 'group')) {
+ if ($params['entity']->activity_enable != "no") {
+ $url = "groups/activity/{$params['entity']->guid}";
+ $item = new ElggMenuItem('activity', elgg_echo('groups:activity'), $url);
+ $return[] = $item;
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Add links/info to entity menu particular to group entities
+ */
+function groups_entity_menu_setup($hook, $type, $return, $params) {
+ if (elgg_in_context('widgets')) {
+ return $return;
+ }
+
+ $entity = $params['entity'];
+ $handler = elgg_extract('handler', $params, false);
+ if ($handler != 'groups') {
+ return $return;
+ }
+
+ foreach ($return as $index => $item) {
+ if (in_array($item->getName(), array('access', 'likes', 'edit', 'delete'))) {
+ unset($return[$index]);
+ }
+ }
+
+ // membership type
+ $membership = $entity->membership;
+ if ($membership == ACCESS_PUBLIC) {
+ $mem = elgg_echo("groups:open");
+ } else {
+ $mem = elgg_echo("groups:closed");
+ }
+ $options = array(
+ 'name' => 'membership',
+ 'text' => $mem,
+ 'href' => false,
+ 'priority' => 100,
+ );
+ $return[] = ElggMenuItem::factory($options);
+
+ // number of members
+ $num_members = get_group_members($entity->guid, 10, 0, 0, true);
+ $members_string = elgg_echo('groups:member');
+ $options = array(
+ 'name' => 'members',
+ 'text' => $num_members . ' ' . $members_string,
+ 'href' => false,
+ 'priority' => 200,
+ );
+ $return[] = ElggMenuItem::factory($options);
+
+ // feature link
+ if (elgg_is_admin_logged_in()) {
+ if ($entity->featured_group == "yes") {
+ $url = "action/groups/featured?group_guid={$entity->guid}&action_type=unfeature";
+ $wording = elgg_echo("groups:makeunfeatured");
+ } else {
+ $url = "action/groups/featured?group_guid={$entity->guid}&action_type=feature";
+ $wording = elgg_echo("groups:makefeatured");
+ }
+ $options = array(
+ 'name' => 'feature',
+ 'text' => $wording,
+ 'href' => $url,
+ 'priority' => 300,
+ 'is_action' => true
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+
+ return $return;
+}
+
+/**
+ * Add a remove user link to user hover menu when the page owner is a group
+ */
+function groups_user_entity_menu_setup($hook, $type, $return, $params) {
+ if (elgg_is_logged_in()) {
+ $group = elgg_get_page_owner_entity();
+
+ // Check for valid group
+ if (!elgg_instanceof($group, 'group')) {
+ return $return;
+ }
+
+ $entity = $params['entity'];
+
+ // Make sure we have a user and that user is a member of the group
+ if (!elgg_instanceof($entity, 'user') || !$group->isMember($entity)) {
+ return $return;
+ }
+
+ // Add remove link if we can edit the group, and if we're not trying to remove the group owner
+ if ($group->canEdit() && $group->getOwnerGUID() != $entity->guid) {
+ $remove = elgg_view('output/confirmlink', array(
+ 'href' => "action/groups/remove?user_guid={$entity->guid}&group_guid={$group->guid}",
+ 'text' => elgg_echo('groups:removeuser'),
+ ));
+
+ $options = array(
+ 'name' => 'removeuser',
+ 'text' => $remove,
+ 'priority' => 999,
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Add edit and delete links for forum replies
+ */
+function groups_annotation_menu_setup($hook, $type, $return, $params) {
+ if (elgg_in_context('widgets')) {
+ return $return;
+ }
+
+ $annotation = $params['annotation'];
+
+ if ($annotation->name != 'group_topic_post') {
+ return $return;
+ }
+
+ if ($annotation->canEdit()) {
+ $url = elgg_http_add_url_query_elements('action/discussion/reply/delete', array(
+ 'annotation_id' => $annotation->id,
+ ));
+
+ $options = array(
+ 'name' => 'delete',
+ 'href' => $url,
+ 'text' => "<span class=\"elgg-icon elgg-icon-delete\"></span>",
+ 'confirm' => elgg_echo('deleteconfirm'),
+ 'encode_text' => false
+ );
+ $return[] = ElggMenuItem::factory($options);
+
+ $url = elgg_http_add_url_query_elements('discussion', array(
+ 'annotation_id' => $annotation->id,
+ ));
+
+ $options = array(
+ 'name' => 'edit',
+ 'href' => "#edit-annotation-$annotation->id",
+ 'text' => elgg_echo('edit'),
+ 'encode_text' => false,
+ 'rel' => 'toggle',
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+
+ return $return;
+}
+
+/**
+ * Groups created so create an access list for it
+ */
+function groups_create_event_listener($event, $object_type, $object) {
+ $ac_name = elgg_echo('groups:group') . ": " . $object->name;
+ $group_id = create_access_collection($ac_name, $object->guid);
+ if ($group_id) {
+ $object->group_acl = $group_id;
+ } else {
+ // delete group if access creation fails
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Hook to listen to read access control requests and return all the groups you are a member of.
+ */
+function groups_read_acl_plugin_hook($hook, $entity_type, $returnvalue, $params) {
+ //error_log("READ: " . var_export($returnvalue));
+ $user = elgg_get_logged_in_user_entity();
+ if ($user) {
+ // Not using this because of recursion.
+ // Joining a group automatically add user to ACL,
+ // So just see if they're a member of the ACL.
+ //$membership = get_users_membership($user->guid);
+
+ $members = get_members_of_access_collection($group->group_acl);
+ print_r($members);
+ exit;
+
+ if ($membership) {
+ foreach ($membership as $group)
+ $returnvalue[$user->guid][$group->group_acl] = elgg_echo('groups:group') . ": " . $group->name;
+ return $returnvalue;
+ }
+ }
+}
+
+/**
+ * Return the write access for the current group if the user has write access to it.
+ */
+function groups_write_acl_plugin_hook($hook, $entity_type, $returnvalue, $params) {
+ $page_owner = elgg_get_page_owner_entity();
+ $user_guid = $params['user_id'];
+ $user = get_entity($user_guid);
+ if (!$user) {
+ return $returnvalue;
+ }
+
+ // only insert group access for current group
+ if ($page_owner instanceof ElggGroup) {
+ if ($page_owner->canWriteToContainer($user_guid)) {
+ $returnvalue[$page_owner->group_acl] = elgg_echo('groups:group') . ': ' . $page_owner->name;
+
+ unset($returnvalue[ACCESS_FRIENDS]);
+ }
+ } else {
+ // if the user owns the group, remove all access collections manually
+ // this won't be a problem once the group itself owns the acl.
+ $groups = elgg_get_entities_from_relationship(array(
+ 'relationship' => 'member',
+ 'relationship_guid' => $user_guid,
+ 'inverse_relationship' => FALSE,
+ 'limit' => false
+ ));
+
+ if ($groups) {
+ foreach ($groups as $group) {
+ unset($returnvalue[$group->group_acl]);
+ }
+ }
+ }
+
+ return $returnvalue;
+}
+
+/**
+ * Groups deleted, so remove access lists.
+ */
+function groups_delete_event_listener($event, $object_type, $object) {
+ delete_access_collection($object->group_acl);
+
+ return true;
+}
+
+/**
+ * Listens to a group join event and adds a user to the group's access control
+ *
+ */
+function groups_user_join_event_listener($event, $object_type, $object) {
+
+ $group = $object['group'];
+ $user = $object['user'];
+ $acl = $group->group_acl;
+
+ add_user_to_access_collection($user->guid, $acl);
+
+ return true;
+}
+
+/**
+ * Make sure users are added to the access collection
+ */
+function groups_access_collection_override($hook, $entity_type, $returnvalue, $params) {
+ if (isset($params['collection'])) {
+ if (elgg_instanceof(get_entity($params['collection']->owner_guid), 'group')) {
+ return true;
+ }
+ }
+}
+
+/**
+ * Listens to a group leave event and removes a user from the group's access control
+ *
+ */
+function groups_user_leave_event_listener($event, $object_type, $object) {
+
+ $group = $object['group'];
+ $user = $object['user'];
+ $acl = $group->group_acl;
+
+ remove_user_from_access_collection($user->guid, $acl);
+
+ return true;
+}
+
+/**
+ * Grabs groups by invitations
+ * Have to override all access until there's a way override access to getter functions.
+ *
+ * @param int $user_guid The user's guid
+ * @param bool $return_guids Return guids rather than ElggGroup objects
+ *
+ * @return array ElggGroups or guids depending on $return_guids
+ */
+function groups_get_invited_groups($user_guid, $return_guids = FALSE) {
+ $ia = elgg_set_ignore_access(TRUE);
+ $groups = elgg_get_entities_from_relationship(array(
+ 'relationship' => 'invited',
+ 'relationship_guid' => $user_guid,
+ 'inverse_relationship' => TRUE,
+ 'limit' => 0,
+ ));
+ elgg_set_ignore_access($ia);
+
+ if ($return_guids) {
+ $guids = array();
+ foreach ($groups as $group) {
+ $guids[] = $group->getGUID();
+ }
+
+ return $guids;
+ }
+
+ return $groups;
+}
+
+/**
+ * Join a user to a group, add river event, clean-up invitations
+ *
+ * @param ElggGroup $group
+ * @param ElggUser $user
+ * @return bool
+ */
+function groups_join_group($group, $user) {
+
+ // access ignore so user can be added to access collection of invisible group
+ $ia = elgg_set_ignore_access(TRUE);
+ $result = $group->join($user);
+ elgg_set_ignore_access($ia);
+
+ if ($result) {
+ // flush user's access info so the collection is added
+ get_access_list($user->guid, 0, true);
+
+ // Remove any invite or join request flags
+ remove_entity_relationship($group->guid, 'invited', $user->guid);
+ remove_entity_relationship($user->guid, 'membership_request', $group->guid);
+
+ add_to_river('river/relationship/member/create', 'join', $user->guid, $group->guid);
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Function to use on groups for access. It will house private, loggedin, public,
+ * and the group itself. This is when you don't want other groups or access lists
+ * in the access options available.
+ *
+ * @return array
+ */
+function group_access_options($group) {
+ $access_array = array(
+ ACCESS_PRIVATE => 'private',
+ ACCESS_LOGGED_IN => 'logged in users',
+ ACCESS_PUBLIC => 'public',
+ $group->group_acl => elgg_echo('groups:acl', array($group->name)),
+ );
+ return $access_array;
+}
+
+function activity_profile_menu($hook, $entity_type, $return_value, $params) {
+
+ if ($params['owner'] instanceof ElggGroup) {
+ $return_value[] = array(
+ 'text' => elgg_echo('Activity'),
+ 'href' => "groups/activity/{$params['owner']->getGUID()}"
+ );
+ }
+ return $return_value;
+}
+
+/**
+ * Parse ECML on group discussion views
+ */
+function groups_ecml_views_hook($hook, $entity_type, $return_value, $params) {
+ $return_value['forum/viewposts'] = elgg_echo('groups:ecml:discussion');
+
+ return $return_value;
+}
+
+/**
+ * Parse ECML on group profiles
+ */
+function groupprofile_ecml_views_hook($hook, $entity_type, $return_value, $params) {
+ $return_value['groups/groupprofile'] = elgg_echo('groups:ecml:groupprofile');
+
+ return $return_value;
+}
+
+
+
+/**
+ * Discussion
+ *
+ */
+
+elgg_register_event_handler('init', 'system', 'discussion_init');
+
+/**
+ * Initialize the discussion component
+ */
+function discussion_init() {
+
+ elgg_register_library('elgg:discussion', elgg_get_plugins_path() . 'groups/lib/discussion.php');
+
+ elgg_register_page_handler('discussion', 'discussion_page_handler');
+ elgg_register_page_handler('forum', 'discussion_forum_page_handler');
+
+ elgg_register_entity_url_handler('object', 'groupforumtopic', 'discussion_override_topic_url');
+
+ // commenting not allowed on discussion topics (use a different annotation)
+ elgg_register_plugin_hook_handler('permissions_check:comment', 'object', 'discussion_comment_override');
+
+ $action_base = elgg_get_plugins_path() . 'groups/actions/discussion';
+ elgg_register_action('discussion/save', "$action_base/save.php");
+ elgg_register_action('discussion/delete', "$action_base/delete.php");
+ elgg_register_action('discussion/reply/save', "$action_base/reply/save.php");
+ elgg_register_action('discussion/reply/delete', "$action_base/reply/delete.php");
+
+ // add link to owner block
+ elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'discussion_owner_block_menu');
+
+ // Register for search.
+ elgg_register_entity_type('object', 'groupforumtopic');
+
+ // because replies are not comments, need of our menu item
+ elgg_register_plugin_hook_handler('register', 'menu:river', 'discussion_add_to_river_menu');
+
+ // add the forum tool option
+ add_group_tool_option('forum', elgg_echo('groups:enableforum'), true);
+ elgg_extend_view('groups/tool_latest', 'discussion/group_module');
+
+ // notifications
+ register_notification_object('object', 'groupforumtopic', elgg_echo('discussion:notification:topic:subject'));
+ elgg_register_plugin_hook_handler('notify:entity:message', 'object', 'groupforumtopic_notify_message');
+ elgg_register_event_handler('create', 'annotation', 'discussion_reply_notifications');
+ elgg_register_plugin_hook_handler('notify:annotation:message', 'group_topic_post', 'discussion_create_reply_notification');
+}
+
+/**
+ * Exists for backwards compatibility for Elgg 1.7
+ */
+function discussion_forum_page_handler($page) {
+ switch ($page[0]) {
+ case 'topic':
+ header('Status: 301 Moved Permanently');
+ forward("/discussion/view/{$page[1]}/{$page[2]}");
+ break;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Discussion page handler
+ *
+ * URLs take the form of
+ * All topics in site: discussion/all
+ * List topics in forum: discussion/owner/<guid>
+ * View discussion topic: discussion/view/<guid>
+ * Add discussion topic: discussion/add/<guid>
+ * Edit discussion topic: discussion/edit/<guid>
+ *
+ * @param array $page Array of url segments for routing
+ * @return bool
+ */
+function discussion_page_handler($page) {
+
+ elgg_load_library('elgg:discussion');
+
+ if (!isset($page[0])) {
+ $page[0] = 'all';
+ }
+
+ elgg_push_breadcrumb(elgg_echo('discussion'), 'discussion/all');
+
+ switch ($page[0]) {
+ case 'all':
+ discussion_handle_all_page();
+ break;
+ case 'owner':
+ discussion_handle_list_page($page[1]);
+ break;
+ case 'add':
+ discussion_handle_edit_page('add', $page[1]);
+ break;
+ case 'edit':
+ discussion_handle_edit_page('edit', $page[1]);
+ break;
+ case 'view':
+ discussion_handle_view_page($page[1]);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Override the discussion topic url
+ *
+ * @param ElggObject $entity Discussion topic
+ * @return string
+ */
+function discussion_override_topic_url($entity) {
+ return 'discussion/view/' . $entity->guid . '/' . elgg_get_friendly_title($entity->title);
+}
+
+/**
+ * We don't want people commenting on topics in the river
+ */
+function discussion_comment_override($hook, $type, $return, $params) {
+ if (elgg_instanceof($params['entity'], 'object', 'groupforumtopic')) {
+ return false;
+ }
+}
+
+/**
+ * Add owner block link
+ */
+function discussion_owner_block_menu($hook, $type, $return, $params) {
+ if (elgg_instanceof($params['entity'], 'group')) {
+ if ($params['entity']->forum_enable != "no") {
+ $url = "discussion/owner/{$params['entity']->guid}";
+ $item = new ElggMenuItem('discussion', elgg_echo('discussion:group'), $url);
+ $return[] = $item;
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Add the reply button for the river
+ */
+function discussion_add_to_river_menu($hook, $type, $return, $params) {
+ if (elgg_is_logged_in() && !elgg_in_context('widgets')) {
+ $item = $params['item'];
+ $object = $item->getObjectEntity();
+ if (elgg_instanceof($object, 'object', 'groupforumtopic')) {
+ if ($item->annotation_id == 0) {
+ $group = $object->getContainerEntity();
+ if ($group && ($group->canWriteToContainer() || elgg_is_admin_logged_in())) {
+ $options = array(
+ 'name' => 'reply',
+ 'href' => "#groups-reply-$object->guid",
+ 'text' => elgg_view_icon('speech-bubble'),
+ 'title' => elgg_echo('reply:this'),
+ 'rel' => 'toggle',
+ 'priority' => 50,
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+ }
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Create discussion notification body
+ *
+ * @todo namespace method with 'discussion'
+ *
+ * @param string $hook
+ * @param string $type
+ * @param string $message
+ * @param array $params
+ */
+function groupforumtopic_notify_message($hook, $type, $message, $params) {
+ $entity = $params['entity'];
+ $to_entity = $params['to_entity'];
+ $method = $params['method'];
+
+ if (($entity instanceof ElggEntity) && ($entity->getSubtype() == 'groupforumtopic')) {
+ $descr = $entity->description;
+ $title = $entity->title;
+ $url = $entity->getURL();
+ $owner = $entity->getOwnerEntity();
+ $group = $entity->getContainerEntity();
+
+ return elgg_echo('groups:notification', array(
+ $owner->name,
+ $group->name,
+ $entity->title,
+ $entity->description,
+ $entity->getURL()
+ ));
+ }
+
+ return null;
+}
+
+/**
+ * Create discussion reply notification body
+ *
+ * @param string $hook
+ * @param string $type
+ * @param string $message
+ * @param array $params
+ */
+function discussion_create_reply_notification($hook, $type, $message, $params) {
+ $reply = $params['annotation'];
+ $method = $params['method'];
+ $topic = $reply->getEntity();
+ $poster = $reply->getOwnerEntity();
+ $group = $topic->getContainerEntity();
+
+ return elgg_echo('discussion:notification:reply:body', array(
+ $poster->name,
+ $topic->title,
+ $group->name,
+ $reply->value,
+ $topic->getURL(),
+ ));
+}
+
+/**
+ * Catch reply to discussion topic and generate notifications
+ *
+ * @todo this will be replaced in Elgg 1.9 and is a clone of object_notifications()
+ *
+ * @param string $event
+ * @param string $type
+ * @param ElggAnnotation $annotation
+ * @return void
+ */
+function discussion_reply_notifications($event, $type, $annotation) {
+ global $CONFIG, $NOTIFICATION_HANDLERS;
+
+ if ($annotation->name !== 'group_topic_post') {
+ return;
+ }
+
+ // Have we registered notifications for this type of entity?
+ $object_type = 'object';
+ $object_subtype = 'groupforumtopic';
+
+ $topic = $annotation->getEntity();
+ if (!$topic) {
+ return;
+ }
+
+ $poster = $annotation->getOwnerEntity();
+ if (!$poster) {
+ return;
+ }
+
+ if (isset($CONFIG->register_objects[$object_type][$object_subtype])) {
+ $subject = $CONFIG->register_objects[$object_type][$object_subtype];
+ $string = $subject . ": " . $topic->getURL();
+
+ // Get users interested in content from this person and notify them
+ // (Person defined by container_guid so we can also subscribe to groups if we want)
+ foreach ($NOTIFICATION_HANDLERS as $method => $foo) {
+ $interested_users = elgg_get_entities_from_relationship(array(
+ 'relationship' => 'notify' . $method,
+ 'relationship_guid' => $topic->getContainerGUID(),
+ 'inverse_relationship' => true,
+ 'type' => 'user',
+ 'limit' => 0,
+ ));
+
+ if ($interested_users && is_array($interested_users)) {
+ foreach ($interested_users as $user) {
+ if ($user instanceof ElggUser && !$user->isBanned()) {
+ if (($user->guid != $poster->guid) && has_access_to_entity($topic, $user) && $topic->access_id != ACCESS_PRIVATE) {
+ $body = elgg_trigger_plugin_hook('notify:annotation:message', $annotation->getSubtype(), array(
+ 'annotation' => $annotation,
+ 'to_entity' => $user,
+ 'method' => $method), $string);
+ if (empty($body) && $body !== false) {
+ $body = $string;
+ }
+ if ($body !== false) {
+ notify_user($user->guid, $topic->getContainerGUID(), $subject, $body, null, array($method));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * A simple function to see who can edit a group discussion post
+ * @param the comment $entity
+ * @param user who owns the group $group_owner
+ * @return boolean
+ */
+function groups_can_edit_discussion($entity, $group_owner) {
+
+ //logged in user
+ $user = elgg_get_logged_in_user_guid();
+
+ if (($entity->owner_guid == $user) || $group_owner == $user || elgg_is_admin_logged_in()) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Process upgrades for the groups plugin
+ */
+function groups_run_upgrades() {
+ $path = elgg_get_plugins_path() . 'groups/upgrades/';
+ $files = elgg_get_upgrade_files($path);
+ foreach ($files as $file) {
+ include "$path{$file}";
+ }
+}
diff --git a/mod/groups/topicposts.php b/mod/groups/topicposts.php
new file mode 100644
index 000000000..d0137e2f5
--- /dev/null
+++ b/mod/groups/topicposts.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Elgg Groups topic posts page
+ *
+ * @package ElggGroups
+ *
+ * @deprecated 1.8
+ */
+
+// Load Elgg engine
+require_once(dirname(dirname(dirname(__FILE__))) . "/engine/start.php");
+
+elgg_load_library('elgg:discussion');
+
+$guid = get_input('topic');
+
+register_error(elgg_echo('changebookmark'));
+
+forward("/discussion/view/$guid");
diff --git a/mod/groups/upgrades/2011030101.php b/mod/groups/upgrades/2011030101.php
new file mode 100644
index 000000000..3199d76ba
--- /dev/null
+++ b/mod/groups/upgrades/2011030101.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Move text of first annotation to group forum topic object and delete annotation
+ *
+ * First determine if the upgrade is needed and then if needed, batch the update
+ */
+
+$topics = elgg_get_entities(array(
+ 'type' => 'object',
+ 'subtype' => 'groupforumtopic',
+ 'limit' => 5,
+ 'order_by' => 'e.time_created asc',
+));
+
+// if not topics, no upgrade required
+if (!$topics) {
+ return;
+}
+
+// if all five of the topics have empty descriptions, we need to upgrade
+foreach ($topics as $topic) {
+ if ($topic->description) {
+ return;
+ }
+}
+
+
+/**
+ * Condense first annotation into object
+ *
+ * @param ElggObject $topic
+ */
+function groups_2011030101($topic) {
+
+ // do not upgrade topics that have already been upgraded
+ if ($topic->description) {
+ return true;
+ }
+
+ $annotation = $topic->getAnnotations('group_topic_post', 1);
+ if (!$annotation) {
+ // no text for this forum post so we delete (probably caused by #2624)
+ $topic->delete();
+ return;
+ }
+
+ $topic->description = $annotation[0]->value;
+ $topic->save();
+
+ return $annotation[0]->delete();
+}
+
+$previous_access = elgg_set_ignore_access(true);
+$options = array(
+ 'type' => 'object',
+ 'subtype' => 'groupforumtopic',
+ 'limit' => 0,
+);
+$batch = new ElggBatch('elgg_get_entities', $options, 'groups_2011030101', 100);
+elgg_set_ignore_access($previous_access);
+
+if ($batch->callbackResult) {
+ error_log("Elgg Groups upgrade (2011030101) succeeded");
+} else {
+ error_log("Elgg Groups upgrade (2011030101) failed");
+}
diff --git a/mod/groups/views/default/annotation/group_topic_post.php b/mod/groups/views/default/annotation/group_topic_post.php
new file mode 100644
index 000000000..f38d2a77a
--- /dev/null
+++ b/mod/groups/views/default/annotation/group_topic_post.php
@@ -0,0 +1,19 @@
+<?php
+/*
+ * Embeds an edit link for the annotation
+ */
+
+$annotation = elgg_extract('annotation', $vars);
+
+echo elgg_view('annotation/default', $vars);
+
+if ($annotation->canEdit()) {
+ $form = elgg_view_form('discussion/reply/save', array(), array_merge(array(
+ 'entity' => get_entity($annotation->entity_guid),
+ 'annotation' => $annotation
+ ), $vars)
+ );
+
+ echo "<div class=\"hidden mbm\" id=\"edit-annotation-$annotation->id\">$form</div>";
+}
+
diff --git a/mod/groups/views/default/discussion/closed.php b/mod/groups/views/default/discussion/closed.php
new file mode 100644
index 000000000..78bca108b
--- /dev/null
+++ b/mod/groups/views/default/discussion/closed.php
@@ -0,0 +1,6 @@
+<?php
+/**
+ * Topic is closed
+ */
+echo "<h3>" . elgg_echo("groups:topicisclosed") . "</h3>";
+echo "<p>" . elgg_echo("groups:topiccloseddesc") . "</p>"; \ No newline at end of file
diff --git a/mod/groups/views/default/discussion/group_module.php b/mod/groups/views/default/discussion/group_module.php
new file mode 100644
index 000000000..e0bcd55d6
--- /dev/null
+++ b/mod/groups/views/default/discussion/group_module.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Latest forum posts
+ *
+ * @uses $vars['entity']
+ */
+
+if ($vars['entity']->forum_enable == 'no') {
+ return true;
+}
+
+$group = $vars['entity'];
+
+
+$all_link = elgg_view('output/url', array(
+ 'href' => "discussion/owner/$group->guid",
+ 'text' => elgg_echo('link:view:all'),
+ 'is_trusted' => true,
+));
+
+elgg_push_context('widgets');
+$options = array(
+ 'type' => 'object',
+ 'subtype' => 'groupforumtopic',
+ 'container_guid' => $group->getGUID(),
+ 'limit' => 6,
+ 'full_view' => false,
+ 'pagination' => false,
+);
+$content = elgg_list_entities($options);
+elgg_pop_context();
+
+if (!$content) {
+ $content = '<p>' . elgg_echo('discussion:none') . '</p>';
+}
+
+$new_link = elgg_view('output/url', array(
+ 'href' => "discussion/add/" . $group->getGUID(),
+ 'text' => elgg_echo('groups:addtopic'),
+ 'is_trusted' => true,
+));
+
+echo elgg_view('groups/profile/module', array(
+ 'title' => elgg_echo('discussion:group'),
+ 'content' => $content,
+ 'all_link' => $all_link,
+ 'add_link' => $new_link,
+)); \ No newline at end of file
diff --git a/mod/groups/views/default/discussion/replies.php b/mod/groups/views/default/discussion/replies.php
new file mode 100644
index 000000000..2bfb6f0cd
--- /dev/null
+++ b/mod/groups/views/default/discussion/replies.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * List replies with optional add form
+ *
+ * @uses $vars['entity'] ElggEntity
+ * @uses $vars['show_add_form'] Display add form or not
+ */
+
+$show_add_form = elgg_extract('show_add_form', $vars, true);
+
+echo '<div id="group-replies" class="mtl">';
+
+$options = array(
+ 'guid' => $vars['entity']->getGUID(),
+ 'annotation_name' => 'group_topic_post',
+);
+$html = elgg_list_annotations($options);
+if ($html) {
+ echo '<h3>' . elgg_echo('group:replies') . '</h3>';
+ echo $html;
+}
+
+if ($show_add_form) {
+ $form_vars = array('class' => 'mtm');
+ echo elgg_view_form('discussion/reply/save', $form_vars, $vars);
+}
+
+echo '</div>';
diff --git a/mod/groups/views/default/forms/discussion/reply/save.php b/mod/groups/views/default/forms/discussion/reply/save.php
new file mode 100644
index 000000000..083fefb78
--- /dev/null
+++ b/mod/groups/views/default/forms/discussion/reply/save.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Discussion topic reply form body
+ *
+ * @uses $vars['entity'] A discussion topic object
+ * @uses $vars['inline'] Display a shortened form?
+ */
+
+if (isset($vars['entity']) && elgg_is_logged_in()) {
+ echo elgg_view('input/hidden', array(
+ 'name' => 'entity_guid',
+ 'value' => $vars['entity']->getGUID(),
+ ));
+
+ $inline = elgg_extract('inline', $vars, false);
+
+ $annotation = elgg_extract('annotation', $vars);
+
+ $value = '';
+
+ if ($annotation) {
+ $value = $annotation->value;
+ echo elgg_view('input/hidden', array(
+ 'name' => 'annotation_id',
+ 'value' => $annotation->id
+ ));
+ }
+
+ if ($inline) {
+ echo elgg_view('input/text', array('name' => 'group_topic_post', 'value' => $value));
+ echo elgg_view('input/submit', array('value' => elgg_echo('reply')));
+ } else {
+?>
+ <div>
+ <label>
+ <?php
+ if ($annotation) {
+ echo elgg_echo('edit');
+ } else {
+ echo elgg_echo("reply");
+ }
+ ?>
+ </label>
+ <?php echo elgg_view('input/longtext', array('name' => 'group_topic_post', 'value' => $value)); ?>
+ </div>
+ <div class="elgg-foot">
+<?php
+ if ($annotation) {
+ echo elgg_view('input/submit', array('value' => elgg_echo('save')));
+ } else {
+ echo elgg_view('input/submit', array('value' => elgg_echo('reply')));
+ }
+?>
+ </div>
+<?php
+ }
+}
diff --git a/mod/groups/views/default/forms/discussion/save.php b/mod/groups/views/default/forms/discussion/save.php
new file mode 100644
index 000000000..a6582ede7
--- /dev/null
+++ b/mod/groups/views/default/forms/discussion/save.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Discussion topic add/edit form body
+ *
+ */
+
+$title = elgg_extract('title', $vars, '');
+$desc = elgg_extract('description', $vars, '');
+$status = elgg_extract('status', $vars, '');
+$tags = elgg_extract('tags', $vars, '');
+$access_id = elgg_extract('access_id', $vars, ACCESS_DEFAULT);
+$container_guid = elgg_extract('container_guid', $vars);
+$guid = elgg_extract('guid', $vars, null);
+
+?>
+<div>
+ <label><?php echo elgg_echo('title'); ?></label><br />
+ <?php echo elgg_view('input/text', array('name' => 'title', 'value' => $title)); ?>
+</div>
+<div>
+ <label><?php echo elgg_echo('groups:topicmessage'); ?></label>
+ <?php echo elgg_view('input/longtext', array('name' => 'description', 'value' => $desc)); ?>
+</div>
+<div>
+ <label><?php echo elgg_echo('tags'); ?></label>
+ <?php echo elgg_view('input/tags', array('name' => 'tags', 'value' => $tags)); ?>
+</div>
+<div>
+ <label><?php echo elgg_echo("groups:topicstatus"); ?></label><br />
+ <?php
+ echo elgg_view('input/dropdown', array(
+ 'name' => 'status',
+ 'value' => $status,
+ 'options_values' => array(
+ 'open' => elgg_echo('groups:topicopen'),
+ 'closed' => elgg_echo('groups:topicclosed'),
+ ),
+ ));
+ ?>
+</div>
+<div>
+ <label><?php echo elgg_echo('access'); ?></label><br />
+ <?php echo elgg_view('input/access', array('name' => 'access_id', 'value' => $access_id)); ?>
+</div>
+<div class="elgg-foot">
+<?php
+
+echo elgg_view('input/hidden', array('name' => 'container_guid', 'value' => $container_guid));
+
+if ($guid) {
+ echo elgg_view('input/hidden', array('name' => 'topic_guid', 'value' => $guid));
+}
+
+echo elgg_view('input/submit', array('value' => elgg_echo("save")));
+
+?>
+</div>
diff --git a/mod/groups/views/default/forms/groups/edit.php b/mod/groups/views/default/forms/groups/edit.php
new file mode 100644
index 000000000..e2dc5455a
--- /dev/null
+++ b/mod/groups/views/default/forms/groups/edit.php
@@ -0,0 +1,178 @@
+<?php
+/**
+ * Group edit form
+ *
+ * @package ElggGroups
+ */
+
+// only extract these elements.
+$name = $membership = $vis = $entity = null;
+extract($vars, EXTR_IF_EXISTS);
+
+?>
+<div>
+ <label><?php echo elgg_echo("groups:icon"); ?></label><br />
+ <?php echo elgg_view("input/file", array('name' => 'icon')); ?>
+</div>
+<div>
+ <label><?php echo elgg_echo("groups:name"); ?></label><br />
+ <?php echo elgg_view("input/text", array(
+ 'name' => 'name',
+ 'value' => $name
+ ));
+ ?>
+</div>
+<?php
+
+$group_profile_fields = elgg_get_config('group');
+if ($group_profile_fields > 0) {
+ foreach ($group_profile_fields as $shortname => $valtype) {
+ $line_break = '<br />';
+ if ($valtype == 'longtext') {
+ $line_break = '';
+ }
+ echo '<div><label>';
+ echo elgg_echo("groups:{$shortname}");
+ echo "</label>$line_break";
+ echo elgg_view("input/{$valtype}", array(
+ 'name' => $shortname,
+ 'value' => elgg_extract($shortname, $vars)
+ ));
+ echo '</div>';
+ }
+}
+?>
+
+<div>
+ <label>
+ <?php echo elgg_echo('groups:membership'); ?><br />
+ <?php echo elgg_view('input/dropdown', array(
+ 'name' => 'membership',
+ 'value' => $membership,
+ 'options_values' => array(
+ ACCESS_PRIVATE => elgg_echo('groups:access:private'),
+ ACCESS_PUBLIC => elgg_echo('groups:access:public')
+ )
+ ));
+ ?>
+ </label>
+</div>
+
+<?php
+
+if (elgg_get_plugin_setting('hidden_groups', 'groups') == 'yes') {
+ $access_options = array(
+ ACCESS_PRIVATE => elgg_echo('groups:access:group'),
+ ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"),
+ ACCESS_PUBLIC => elgg_echo("PUBLIC")
+ );
+?>
+
+<div>
+ <label>
+ <?php echo elgg_echo('groups:visibility'); ?><br />
+ <?php echo elgg_view('input/access', array(
+ 'name' => 'vis',
+ 'value' => $vis,
+ 'options_values' => $access_options,
+ ));
+ ?>
+ </label>
+</div>
+
+<?php
+}
+
+if (isset($vars['entity'])) {
+ $entity = $vars['entity'];
+ $owner_guid = $vars['entity']->owner_guid;
+} else {
+ $entity = false;
+}
+
+if ($entity && ($owner_guid == elgg_get_logged_in_user_guid() || elgg_is_admin_logged_in())) {
+ $members = array();
+
+ $options = array(
+ 'relationship' => 'member',
+ 'relationship_guid' => $vars['entity']->getGUID(),
+ 'inverse_relationship' => true,
+ 'type' => 'user',
+ 'limit' => 0,
+ );
+
+ $batch = new ElggBatch('elgg_get_entities_from_relationship', $options);
+ foreach ($batch as $member) {
+ $members[$member->guid] = "$member->name (@$member->username)";
+ }
+?>
+
+<div>
+ <label>
+ <?php echo elgg_echo('groups:owner'); ?><br />
+ <?php echo elgg_view('input/dropdown', array(
+ 'name' => 'owner_guid',
+ 'value' => $owner_guid,
+ 'options_values' => $members,
+ 'class' => 'groups-owner-input',
+ ));
+ ?>
+ </label>
+ <?php
+ if ($owner_guid == elgg_get_logged_in_user_guid()) {
+ echo '<span class="elgg-text-help">' . elgg_echo('groups:owner:warning') . '</span>';
+ }
+ ?>
+</div>
+
+<?php
+}
+
+$tools = elgg_get_config('group_tool_options');
+if ($tools) {
+ usort($tools, create_function('$a,$b', 'return strcmp($a->label,$b->label);'));
+ foreach ($tools as $group_option) {
+ $group_option_toggle_name = $group_option->name . "_enable";
+ $value = elgg_extract($group_option_toggle_name, $vars);
+?>
+<div>
+ <label>
+ <?php echo $group_option->label; ?><br />
+ </label>
+ <?php echo elgg_view("input/radio", array(
+ "name" => $group_option_toggle_name,
+ "value" => $value,
+ 'options' => array(
+ elgg_echo('groups:yes') => 'yes',
+ elgg_echo('groups:no') => 'no',
+ ),
+ ));
+ ?>
+</div>
+<?php
+ }
+}
+?>
+<div class="elgg-foot">
+<?php
+
+if ($entity) {
+ echo elgg_view('input/hidden', array(
+ 'name' => 'group_guid',
+ 'value' => $entity->getGUID(),
+ ));
+}
+
+echo elgg_view('input/submit', array('value' => elgg_echo('save')));
+
+if ($entity) {
+ $delete_url = 'action/groups/delete?guid=' . $entity->getGUID();
+ echo elgg_view('output/confirmlink', array(
+ 'text' => elgg_echo('groups:delete'),
+ 'href' => $delete_url,
+ 'confirm' => elgg_echo('groups:deletewarning'),
+ 'class' => 'elgg-button elgg-button-delete float-alt',
+ ));
+}
+?>
+</div>
diff --git a/mod/groups/views/default/forms/groups/find.php b/mod/groups/views/default/forms/groups/find.php
new file mode 100644
index 000000000..ddf639b74
--- /dev/null
+++ b/mod/groups/views/default/forms/groups/find.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Group tag-based search form body
+ */
+
+$tag_string = elgg_echo('groups:search:tags');
+
+$params = array(
+ 'name' => 'tag',
+ 'class' => 'elgg-input-search mbm',
+ 'value' => $tag_string,
+ 'onclick' => "if (this.value=='$tag_string') { this.value='' }",
+);
+echo elgg_view('input/text', $params);
+
+echo elgg_view('input/submit', array('value' => elgg_echo('search:go')));
diff --git a/mod/groups/views/default/forms/groups/invite.php b/mod/groups/views/default/forms/groups/invite.php
new file mode 100644
index 000000000..ef3131782
--- /dev/null
+++ b/mod/groups/views/default/forms/groups/invite.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Elgg groups invite form
+ *
+ * @package ElggGroups
+ */
+
+$group = $vars['entity'];
+$owner = $group->getOwnerEntity();
+$forward_url = $group->getURL();
+$friends = elgg_get_logged_in_user_entity()->getFriends('', 0);
+
+if ($friends) {
+ echo elgg_view('input/friendspicker', array('entities' => $friends, 'name' => 'user_guid', 'highlight' => 'all'));
+ echo '<div class="elgg-foot">';
+ echo elgg_view('input/hidden', array('name' => 'forward_url', 'value' => $forward_url));
+ echo elgg_view('input/hidden', array('name' => 'group_guid', 'value' => $group->guid));
+ echo elgg_view('input/submit', array('value' => elgg_echo('invite')));
+ echo '</div>';
+} else {
+ echo elgg_echo('groups:nofriendsatall');
+} \ No newline at end of file
diff --git a/mod/groups/views/default/forms/groups/search.php b/mod/groups/views/default/forms/groups/search.php
new file mode 100644
index 000000000..850b6088e
--- /dev/null
+++ b/mod/groups/views/default/forms/groups/search.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Group search form
+ *
+ * @uses $vars['entity'] ElggGroup
+ */
+
+$params = array(
+ 'name' => 'q',
+ 'class' => 'elgg-input-search mbm',
+ 'value' => $tag_string,
+);
+echo elgg_view('input/text', $params);
+
+echo elgg_view('input/hidden', array(
+ 'name' => 'container_guid',
+ 'value' => $vars['entity']->getGUID(),
+));
+
+echo elgg_view('input/submit', array('value' => elgg_echo('search:go')));
diff --git a/mod/groups/views/default/group/default.php b/mod/groups/views/default/group/default.php
new file mode 100644
index 000000000..d9460dff4
--- /dev/null
+++ b/mod/groups/views/default/group/default.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Group entity view
+ *
+ * @package ElggGroups
+ */
+
+$group = $vars['entity'];
+
+$icon = elgg_view_entity_icon($group, 'tiny');
+
+$metadata = elgg_view_menu('entity', array(
+ 'entity' => $group,
+ 'handler' => 'groups',
+ 'sort_by' => 'priority',
+ 'class' => 'elgg-menu-hz',
+));
+
+if (elgg_in_context('owner_block') || elgg_in_context('widgets')) {
+ $metadata = '';
+}
+
+
+if ($vars['full_view']) {
+ echo elgg_view('groups/profile/summary', $vars);
+} else {
+ // brief view
+ $params = array(
+ 'entity' => $group,
+ 'metadata' => $metadata,
+ 'subtitle' => $group->briefdescription,
+ );
+ $params = $params + $vars;
+ $list_body = elgg_view('group/elements/summary', $params);
+
+ echo elgg_view_image_block($icon, $list_body, $vars);
+}
diff --git a/mod/groups/views/default/groups/css.php b/mod/groups/views/default/groups/css.php
new file mode 100644
index 000000000..32dd2b74d
--- /dev/null
+++ b/mod/groups/views/default/groups/css.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Elgg Groups css
+ *
+ * @package groups
+ */
+
+?>
+.groups-profile > .elgg-image {
+ margin-right: 10px;
+}
+.groups-stats {
+ background: #eeeeee;
+ padding: 5px;
+ margin-top: 10px;
+
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+
+.groups-profile-fields .odd,
+.groups-profile-fields .even {
+ background: #f4f4f4;
+
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+
+ padding: 2px 4px;
+ margin-bottom: 7px;
+}
+
+.groups-profile-fields .elgg-output {
+ margin: 0;
+}
+
+#groups-tools > li {
+ width: 48%;
+ min-height: 200px;
+ margin-bottom: 40px;
+}
+
+#groups-tools > li:nth-child(odd) {
+ margin-right: 4%;
+}
+
+.groups-widget-viewall {
+ float: right;
+ font-size: 85%;
+}
+
+.groups-latest-reply {
+ float: right;
+}
+
+.elgg-menu-groups-my-status li a {
+ display: block;
+
+ -webkit-border-radius: 8px;
+ -moz-border-radius: 8px;
+ border-radius: 8px;
+
+ background-color: white;
+ margin: 3px 0 5px 0;
+ padding: 2px 4px 2px 8px;
+}
+.elgg-menu-groups-my-status li a:hover {
+ background-color: #0054A7;
+ color: white;
+ text-decoration: none;
+}
+.elgg-menu-groups-my-status li.elgg-state-selected > a {
+ background-color: #4690D6;
+ color: white;
+}
diff --git a/mod/groups/views/default/groups/edit.php b/mod/groups/views/default/groups/edit.php
new file mode 100644
index 000000000..5579ad54a
--- /dev/null
+++ b/mod/groups/views/default/groups/edit.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Edit/create a group wrapper
+ *
+ * @uses $vars['entity'] ElggGroup object
+ */
+
+$entity = elgg_extract('entity', $vars, null);
+
+$form_vars = array(
+ 'enctype' => 'multipart/form-data',
+ 'class' => 'elgg-form-alt',
+);
+
+echo elgg_view_form('groups/edit', $form_vars, groups_prepare_form_vars($entity));
diff --git a/mod/groups/views/default/groups/group_sort_menu.php b/mod/groups/views/default/groups/group_sort_menu.php
new file mode 100644
index 000000000..f5631a31f
--- /dev/null
+++ b/mod/groups/views/default/groups/group_sort_menu.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * All groups listing page navigation
+ *
+ * @uses $vars['selected'] Name of the tab that has been selected
+ */
+
+$tabs = array(
+ 'newest' => array(
+ 'text' => elgg_echo('groups:newest'),
+ 'href' => 'groups/all?filter=newest',
+ 'priority' => 200,
+ ),
+ 'popular' => array(
+ 'text' => elgg_echo('groups:popular'),
+ 'href' => 'groups/all?filter=popular',
+ 'priority' => 300,
+ ),
+ 'discussion' => array(
+ 'text' => elgg_echo('groups:latestdiscussion'),
+ 'href' => 'groups/all?filter=discussion',
+ 'priority' => 400,
+ ),
+);
+
+foreach ($tabs as $name => $tab) {
+ $tab['name'] = $name;
+
+ if ($vars['selected'] == $name) {
+ $tab['selected'] = true;
+ }
+
+ elgg_register_menu_item('filter', $tab);
+}
+
+echo elgg_view_menu('filter', array('sort_by' => 'priority', 'class' => 'elgg-menu-hz'));
diff --git a/mod/groups/views/default/groups/invitationrequests.php b/mod/groups/views/default/groups/invitationrequests.php
new file mode 100644
index 000000000..94dbdf1f2
--- /dev/null
+++ b/mod/groups/views/default/groups/invitationrequests.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * A user's group invitations
+ *
+ * @uses $vars['invitations'] Array of ElggGroups
+ */
+
+if (!empty($vars['invitations']) && is_array($vars['invitations'])) {
+ $user = elgg_get_logged_in_user_entity();
+ echo '<ul class="elgg-list">';
+ foreach ($vars['invitations'] as $group) {
+ if ($group instanceof ElggGroup) {
+ $icon = elgg_view_entity_icon($group, 'tiny', array('use_hover' => 'true'));
+
+ $group_title = elgg_view('output/url', array(
+ 'href' => $group->getURL(),
+ 'text' => $group->name,
+ 'is_trusted' => true,
+ ));
+
+ $url = elgg_add_action_tokens_to_url(elgg_get_site_url()."action/groups/join?user_guid={$user->guid}&group_guid={$group->guid}");
+ $accept_button = elgg_view('output/url', array(
+ 'href' => $url,
+ 'text' => elgg_echo('accept'),
+ 'class' => 'elgg-button elgg-button-submit',
+ 'is_trusted' => true,
+ ));
+
+ $url = "action/groups/killinvitation?user_guid={$user->getGUID()}&group_guid={$group->getGUID()}";
+ $delete_button = elgg_view('output/confirmlink', array(
+ 'href' => $url,
+ 'confirm' => elgg_echo('groups:invite:remove:check'),
+ 'text' => elgg_echo('delete'),
+ 'class' => 'elgg-button elgg-button-delete mlm',
+ ));
+
+ $body = <<<HTML
+<h4>$group_title</h4>
+<p class="elgg-subtext">$group->briefdescription</p>
+HTML;
+ $alt = $accept_button . $delete_button;
+
+ echo '<li class="pvs">';
+ echo elgg_view_image_block($icon, $body, array('image_alt' => $alt));
+ echo '</li>';
+ }
+ }
+ echo '</ul>';
+} else {
+ echo '<p class="mtm">' . elgg_echo('groups:invitations:none') . "</p>";
+}
diff --git a/mod/groups/views/default/groups/js.php b/mod/groups/views/default/groups/js.php
new file mode 100644
index 000000000..0319be14a
--- /dev/null
+++ b/mod/groups/views/default/groups/js.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Javascript for Groups forms
+ *
+ * @package ElggGroups
+ */
+?>
+
+// this adds a class to support IE8 and older
+elgg.register_hook_handler('init', 'system', function() {
+ // jQuery uses 0-based indexing
+ $('#groups-tools').children('li:even').addClass('odd');
+});
diff --git a/mod/groups/views/default/groups/membershiprequests.php b/mod/groups/views/default/groups/membershiprequests.php
new file mode 100644
index 000000000..2bac0e32b
--- /dev/null
+++ b/mod/groups/views/default/groups/membershiprequests.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * A group's member requests
+ *
+ * @uses $vars['entity'] ElggGroup
+ * @uses $vars['requests'] Array of ElggUsers
+ */
+
+if (!empty($vars['requests']) && is_array($vars['requests'])) {
+ echo '<ul class="elgg-list">';
+ foreach ($vars['requests'] as $user) {
+ $icon = elgg_view_entity_icon($user, 'tiny', array('use_hover' => 'true'));
+
+ $user_title = elgg_view('output/url', array(
+ 'href' => $user->getURL(),
+ 'text' => $user->name,
+ 'is_trusted' => true,
+ ));
+
+ $url = "action/groups/addtogroup?user_guid={$user->guid}&group_guid={$vars['entity']->guid}";
+ $url = elgg_add_action_tokens_to_url($url);
+ $accept_button = elgg_view('output/url', array(
+ 'href' => $url,
+ 'text' => elgg_echo('accept'),
+ 'class' => 'elgg-button elgg-button-submit',
+ 'is_trusted' => true,
+ ));
+
+ $url = 'action/groups/killrequest?user_guid=' . $user->guid . '&group_guid=' . $vars['entity']->guid;
+ $delete_button = elgg_view('output/confirmlink', array(
+ 'href' => $url,
+ 'confirm' => elgg_echo('groups:joinrequest:remove:check'),
+ 'text' => elgg_echo('delete'),
+ 'class' => 'elgg-button elgg-button-delete mlm',
+ ));
+
+ $body = "<h4>$user_title</h4>";
+ $alt = $accept_button . $delete_button;
+
+ echo '<li class="pvs">';
+ echo elgg_view_image_block($icon, $body, array('image_alt' => $alt));
+ echo '</li>';
+ }
+ echo '</ul>';
+} else {
+ echo '<p class="mtm">' . elgg_echo('groups:requests:none') . '</p>';
+}
diff --git a/mod/groups/views/default/groups/profile/activity_module.php b/mod/groups/views/default/groups/profile/activity_module.php
new file mode 100644
index 000000000..832ff4a4b
--- /dev/null
+++ b/mod/groups/views/default/groups/profile/activity_module.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Groups latest activity
+ *
+ * @todo add people joining group to activity
+ *
+ * @package Groups
+ */
+
+if ($vars['entity']->activity_enable == 'no') {
+ return true;
+}
+
+$group = $vars['entity'];
+if (!$group) {
+ return true;
+}
+
+$all_link = elgg_view('output/url', array(
+ 'href' => "groups/activity/$group->guid",
+ 'text' => elgg_echo('link:view:all'),
+ 'is_trusted' => true,
+));
+
+
+elgg_push_context('widgets');
+$db_prefix = elgg_get_config('dbprefix');
+$content = elgg_list_river(array(
+ 'limit' => 4,
+ 'pagination' => false,
+ 'joins' => array("JOIN {$db_prefix}entities e1 ON e1.guid = rv.object_guid"),
+ 'wheres' => array("(e1.container_guid = $group->guid)"),
+));
+elgg_pop_context();
+
+if (!$content) {
+ $content = '<p>' . elgg_echo('groups:activity:none') . '</p>';
+}
+
+echo elgg_view('groups/profile/module', array(
+ 'title' => elgg_echo('groups:activity'),
+ 'content' => $content,
+ 'all_link' => $all_link,
+));
diff --git a/mod/groups/views/default/groups/profile/closed_membership.php b/mod/groups/views/default/groups/profile/closed_membership.php
new file mode 100644
index 000000000..24526d378
--- /dev/null
+++ b/mod/groups/views/default/groups/profile/closed_membership.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Display message about closed membership
+ *
+ * @package ElggGroups
+ */
+
+?>
+<p class="mtm">
+<?php
+echo elgg_echo('groups:closedgroup');
+if (elgg_is_logged_in()) {
+ echo ' ' . elgg_echo('groups:closedgroup:request');
+}
+?>
+</p>
diff --git a/mod/groups/views/default/groups/profile/fields.php b/mod/groups/views/default/groups/profile/fields.php
new file mode 100644
index 000000000..14827f11a
--- /dev/null
+++ b/mod/groups/views/default/groups/profile/fields.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Group profile fields
+ */
+
+$group = $vars['entity'];
+
+$profile_fields = elgg_get_config('group');
+
+if (is_array($profile_fields) && count($profile_fields) > 0) {
+
+ $even_odd = 'odd';
+ foreach ($profile_fields as $key => $valtype) {
+ // do not show the name
+ if ($key == 'name') {
+ continue;
+ }
+
+ $value = $group->$key;
+ if (empty($value)) {
+ continue;
+ }
+
+ $options = array('value' => $group->$key);
+ if ($valtype == 'tags') {
+ $options['tag_names'] = $key;
+ }
+
+ echo "<div class=\"{$even_odd}\">";
+ echo "<b>";
+ echo elgg_echo("groups:$key");
+ echo ": </b>";
+ echo elgg_view("output/$valtype", $options);
+ echo "</div>";
+
+ $even_odd = ($even_odd == 'even') ? 'odd' : 'even';
+ }
+}
diff --git a/mod/groups/views/default/groups/profile/layout.php b/mod/groups/views/default/groups/profile/layout.php
new file mode 100644
index 000000000..f513f10ae
--- /dev/null
+++ b/mod/groups/views/default/groups/profile/layout.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Layout of the groups profile page
+ *
+ * @uses $vars['entity']
+ */
+
+echo elgg_view('groups/profile/summary', $vars);
+if (group_gatekeeper(false)) {
+ echo elgg_view('groups/profile/widgets', $vars);
+} else {
+ echo elgg_view('groups/profile/closed_membership');
+}
diff --git a/mod/groups/views/default/groups/profile/module.php b/mod/groups/views/default/groups/profile/module.php
new file mode 100644
index 000000000..9d0b18266
--- /dev/null
+++ b/mod/groups/views/default/groups/profile/module.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Group module (also called a group widget)
+ *
+ * @uses $vars['title'] The title of the module
+ * @uses $vars['content'] The module content
+ * @uses $vars['all_link'] A link to list content
+ * @uses $vars['add_link'] A link to create content
+ */
+
+$group = elgg_get_page_owner_entity();
+
+$header = "<span class=\"groups-widget-viewall\">{$vars['all_link']}</span>";
+$header .= '<h3>' . $vars['title'] . '</h3>';
+
+if ($group->canWriteToContainer() && isset($vars['add_link'])) {
+ $vars['content'] .= "<span class='elgg-widget-more'>{$vars['add_link']}</span>";
+}
+
+echo '<li>';
+echo elgg_view_module('info', '', $vars['content'], array(
+ 'header' => $header,
+ 'class' => 'elgg-module-group',
+));
+echo '</li>';
diff --git a/mod/groups/views/default/groups/profile/summary.php b/mod/groups/views/default/groups/profile/summary.php
new file mode 100644
index 000000000..3f7496871
--- /dev/null
+++ b/mod/groups/views/default/groups/profile/summary.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Group profile summary
+ *
+ * Icon and profile fields
+ *
+ * @uses $vars['group']
+ */
+
+if (!isset($vars['entity']) || !$vars['entity']) {
+ echo elgg_echo('groups:notfound');
+ return true;
+}
+
+$group = $vars['entity'];
+$owner = $group->getOwnerEntity();
+
+if (!$owner) {
+ // not having an owner is very bad so we throw an exception
+ $msg = elgg_echo('InvalidParameterException:IdNotExistForGUID', array('group owner', $group->guid));
+ throw new InvalidParameterException($msg);
+}
+
+?>
+<div class="groups-profile clearfix elgg-image-block">
+ <div class="elgg-image">
+ <div class="groups-profile-icon">
+ <?php
+ // we don't force icons to be square so don't set width/height
+ echo elgg_view_entity_icon($group, 'large', array(
+ 'href' => '',
+ 'width' => '',
+ 'height' => '',
+ ));
+ ?>
+ </div>
+ <div class="groups-stats">
+ <p>
+ <b><?php echo elgg_echo("groups:owner"); ?>: </b>
+ <?php
+ echo elgg_view('output/url', array(
+ 'text' => $owner->name,
+ 'value' => $owner->getURL(),
+ 'is_trusted' => true,
+ ));
+ ?>
+ </p>
+ <p>
+ <?php
+ echo elgg_echo('groups:members') . ": " . $group->getMembers(0, 0, TRUE);
+ ?>
+ </p>
+ </div>
+ </div>
+
+ <div class="groups-profile-fields elgg-body">
+ <?php
+ echo elgg_view('groups/profile/fields', $vars);
+ ?>
+ </div>
+</div>
+<?php
+?>
+
diff --git a/mod/groups/views/default/groups/profile/widgets.php b/mod/groups/views/default/groups/profile/widgets.php
new file mode 100644
index 000000000..7635cad4f
--- /dev/null
+++ b/mod/groups/views/default/groups/profile/widgets.php
@@ -0,0 +1,24 @@
+<?php
+/**
+* Profile widgets/tools
+*
+* @package ElggGroups
+*/
+
+// tools widget area
+echo '<ul id="groups-tools" class="elgg-gallery elgg-gallery-fluid mtl clearfix">';
+
+// enable tools to extend this area
+echo elgg_view("groups/tool_latest", $vars);
+
+// backward compatibility
+$right = elgg_view('groups/right_column', $vars);
+$left = elgg_view('groups/left_column', $vars);
+if ($right || $left) {
+ elgg_deprecated_notice('The views groups/right_column and groups/left_column have been replaced by groups/tool_latest', 1.8);
+ echo $left;
+ echo $right;
+}
+
+echo "</ul>";
+
diff --git a/mod/groups/views/default/groups/sidebar/featured.php b/mod/groups/views/default/groups/sidebar/featured.php
new file mode 100644
index 000000000..f3f8f8d2d
--- /dev/null
+++ b/mod/groups/views/default/groups/sidebar/featured.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Featured groups
+ *
+ * @package ElggGroups
+ */
+
+$featured_groups = elgg_get_entities_from_metadata(array(
+ 'metadata_name' => 'featured_group',
+ 'metadata_value' => 'yes',
+ 'type' => 'group',
+ 'limit' => 10,
+));
+
+if ($featured_groups) {
+
+ elgg_push_context('widgets');
+ $body = '';
+ foreach ($featured_groups as $group) {
+ $body .= elgg_view_entity($group, array('full_view' => false));
+ }
+ elgg_pop_context();
+
+ echo elgg_view_module('aside', elgg_echo("groups:featured"), $body);
+}
diff --git a/mod/groups/views/default/groups/sidebar/find.php b/mod/groups/views/default/groups/sidebar/find.php
new file mode 100644
index 000000000..c1a8da3c2
--- /dev/null
+++ b/mod/groups/views/default/groups/sidebar/find.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * Group search
+ *
+ * @package ElggGroups
+ */
+$url = elgg_get_site_url() . 'groups/search';
+$body = elgg_view_form('groups/find', array(
+ 'action' => $url,
+ 'method' => 'get',
+ 'disable_security' => true,
+));
+
+echo elgg_view_module('aside', elgg_echo('groups:searchtag'), $body);
diff --git a/mod/groups/views/default/groups/sidebar/members.php b/mod/groups/views/default/groups/sidebar/members.php
new file mode 100644
index 000000000..1199a0c34
--- /dev/null
+++ b/mod/groups/views/default/groups/sidebar/members.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Group members sidebar
+ *
+ * @package ElggGroups
+ *
+ * @uses $vars['entity'] Group entity
+ * @uses $vars['limit'] The number of members to display
+ */
+
+$limit = elgg_extract('limit', $vars, 14);
+
+$all_link = elgg_view('output/url', array(
+ 'href' => 'groups/members/' . $vars['entity']->guid,
+ 'text' => elgg_echo('groups:members:more'),
+ 'is_trusted' => true,
+));
+
+$body = elgg_list_entities_from_relationship(array(
+ 'relationship' => 'member',
+ 'relationship_guid' => $vars['entity']->guid,
+ 'inverse_relationship' => true,
+ 'type' => 'user',
+ 'limit' => $limit,
+ 'list_type' => 'gallery',
+ 'gallery_class' => 'elgg-gallery-users',
+ 'pagination' => false
+));
+
+$body .= "<div class='center mts'>$all_link</div>";
+
+echo elgg_view_module('aside', elgg_echo('groups:members'), $body);
diff --git a/mod/groups/views/default/groups/sidebar/my_status.php b/mod/groups/views/default/groups/sidebar/my_status.php
new file mode 100644
index 000000000..1e4e84b80
--- /dev/null
+++ b/mod/groups/views/default/groups/sidebar/my_status.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Group status for logged in user
+ *
+ * @package ElggGroups
+ *
+ * @uses $vars['entity'] Group entity
+ */
+
+$group = elgg_extract('entity', $vars);
+$user = elgg_get_logged_in_user_entity();
+$subscribed = elgg_extract('subscribed', $vars);
+
+if (!elgg_is_logged_in()) {
+ return true;
+}
+
+// membership status
+$is_member = $group->isMember($user);
+$is_owner = $group->getOwnerEntity() == $user;
+
+if ($is_owner) {
+ elgg_register_menu_item('groups:my_status', array(
+ 'name' => 'membership_status',
+ 'text' => '<a>' . elgg_echo('groups:my_status:group_owner') . '</a>',
+ 'href' => false
+ ));
+} elseif ($is_member) {
+ elgg_register_menu_item('groups:my_status', array(
+ 'name' => 'membership_status',
+ 'text' => '<a>' . elgg_echo('groups:my_status:group_member') . '</a>',
+ 'href' => false
+ ));
+} else {
+ elgg_register_menu_item('groups:my_status', array(
+ 'name' => 'membership_status',
+ 'text' => elgg_echo('groups:join'),
+ 'href' => "/action/groups/join?group_guid={$group->getGUID()}",
+ 'is_action' => true
+ ));
+}
+
+// notification info
+if (elgg_is_active_plugin('notifications') && $is_member) {
+ if ($subscribed) {
+ elgg_register_menu_item('groups:my_status', array(
+ 'name' => 'subscription_status',
+ 'text' => elgg_echo('groups:subscribed'),
+ 'href' => "notifications/group/$user->username",
+ 'is_action' => true
+ ));
+ } else {
+ elgg_register_menu_item('groups:my_status', array(
+ 'name' => 'subscription_status',
+ 'text' => elgg_echo('groups:unsubscribed'),
+ 'href' => "notifications/group/$user->username"
+ ));
+ }
+}
+
+$body = elgg_view_menu('groups:my_status');
+echo elgg_view_module('aside', elgg_echo('groups:my_status'), $body);
diff --git a/mod/groups/views/default/groups/sidebar/search.php b/mod/groups/views/default/groups/sidebar/search.php
new file mode 100644
index 000000000..226835715
--- /dev/null
+++ b/mod/groups/views/default/groups/sidebar/search.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Search for content in this group
+ *
+ * @uses vars['entity'] ElggGroup
+ */
+
+$url = elgg_get_site_url() . 'search';
+$body = elgg_view_form('groups/search', array(
+ 'action' => $url,
+ 'method' => 'get',
+ 'disable_security' => true,
+), $vars);
+
+echo elgg_view_module('aside', elgg_echo('groups:search_in_group'), $body); \ No newline at end of file
diff --git a/mod/groups/views/default/object/groupforumtopic.php b/mod/groups/views/default/object/groupforumtopic.php
new file mode 100644
index 000000000..e6988d16e
--- /dev/null
+++ b/mod/groups/views/default/object/groupforumtopic.php
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Forum topic entity view
+ *
+ * @package ElggGroups
+*/
+
+$full = elgg_extract('full_view', $vars, FALSE);
+$topic = elgg_extract('entity', $vars, FALSE);
+
+if (!$topic) {
+ return true;
+}
+
+$poster = $topic->getOwnerEntity();
+$group = $topic->getContainerEntity();
+$excerpt = elgg_get_excerpt($topic->description);
+
+$poster_icon = elgg_view_entity_icon($poster, 'tiny');
+$poster_link = elgg_view('output/url', array(
+ 'href' => $poster->getURL(),
+ 'text' => $poster->name,
+ 'is_trusted' => true,
+));
+$poster_text = elgg_echo('groups:started', array($poster->name));
+
+$tags = elgg_view('output/tags', array('tags' => $topic->tags));
+$date = elgg_view_friendly_time($topic->time_created);
+
+$replies_link = '';
+$reply_text = '';
+$num_replies = elgg_get_annotations(array(
+ 'annotation_name' => 'group_topic_post',
+ 'guid' => $topic->getGUID(),
+ 'count' => true,
+));
+if ($num_replies != 0) {
+ $last_reply = $topic->getAnnotations('group_topic_post', 1, 0, 'desc');
+ $poster = $last_reply[0]->getOwnerEntity();
+ $reply_time = elgg_view_friendly_time($last_reply[0]->time_created);
+ $reply_text = elgg_echo('groups:updated', array($poster->name, $reply_time));
+
+ $replies_link = elgg_view('output/url', array(
+ 'href' => $topic->getURL() . '#group-replies',
+ 'text' => elgg_echo('group:replies') . " ($num_replies)",
+ 'is_trusted' => true,
+ ));
+}
+
+$metadata = elgg_view_menu('entity', array(
+ 'entity' => $vars['entity'],
+ 'handler' => 'discussion',
+ 'sort_by' => 'priority',
+ 'class' => 'elgg-menu-hz',
+));
+
+// do not show the metadata and controls in widget view
+if (elgg_in_context('widgets')) {
+ $metadata = '';
+}
+
+if ($full) {
+ $subtitle = "$poster_text $date $replies_link";
+
+ $params = array(
+ 'entity' => $topic,
+ 'metadata' => $metadata,
+ 'subtitle' => $subtitle,
+ 'tags' => $tags,
+ );
+ $params = $params + $vars;
+ $list_body = elgg_view('object/elements/summary', $params);
+
+ $info = elgg_view_image_block($poster_icon, $list_body);
+
+ $body = elgg_view('output/longtext', array(
+ 'value' => $topic->description,
+ 'class' => 'clearfix',
+ ));
+
+ echo <<<HTML
+$info
+$body
+HTML;
+
+} else {
+ // brief view
+ $subtitle = "$poster_text $date $replies_link <span class=\"groups-latest-reply\">$reply_text</span>";
+
+ $params = array(
+ 'entity' => $topic,
+ 'metadata' => $metadata,
+ 'subtitle' => $subtitle,
+ 'tags' => $tags,
+ 'content' => $excerpt,
+ );
+ $params = $params + $vars;
+ $list_body = elgg_view('object/elements/summary', $params);
+
+ echo elgg_view_image_block($poster_icon, $list_body);
+}
diff --git a/mod/groups/views/default/plugins/groups/settings.php b/mod/groups/views/default/plugins/groups/settings.php
new file mode 100644
index 000000000..41ea146db
--- /dev/null
+++ b/mod/groups/views/default/plugins/groups/settings.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Groups plugin settings
+ */
+
+// set default value
+if (!isset($vars['entity']->hidden_groups)) {
+ $vars['entity']->hidden_groups = 'no';
+}
+
+// set default value
+if (!isset($vars['entity']->limited_groups)) {
+ $vars['entity']->limited_groups = 'no';
+}
+
+echo '<div>';
+echo elgg_echo('groups:allowhiddengroups');
+echo ' ';
+echo elgg_view('input/dropdown', array(
+ 'name' => 'params[hidden_groups]',
+ 'options_values' => array(
+ 'no' => elgg_echo('option:no'),
+ 'yes' => elgg_echo('option:yes')
+ ),
+ 'value' => $vars['entity']->hidden_groups,
+));
+echo '</div>';
+
+echo '<div>';
+echo elgg_echo('groups:whocancreate');
+echo ' ';
+echo elgg_view('input/dropdown', array(
+ 'name' => 'params[limited_groups]',
+ 'options_values' => array(
+ 'no' => elgg_echo('LOGGED_IN'),
+ 'yes' => elgg_echo('admin')
+ ),
+ 'value' => $vars['entity']->limited_groups,
+));
+echo '</div>';
diff --git a/mod/groups/views/default/river/annotation/group_topic_post/reply.php b/mod/groups/views/default/river/annotation/group_topic_post/reply.php
new file mode 100644
index 000000000..afc823bde
--- /dev/null
+++ b/mod/groups/views/default/river/annotation/group_topic_post/reply.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Reply river view
+ */
+$object = $vars['item']->getObjectEntity();
+$reply = $vars['item']->getAnnotation();
+$excerpt = elgg_get_excerpt($reply->value);
+
+echo elgg_view('river/elements/layout', array(
+ 'item' => $vars['item'],
+ 'message' => $excerpt,
+)); \ No newline at end of file
diff --git a/mod/groups/views/default/river/group/create.php b/mod/groups/views/default/river/group/create.php
new file mode 100644
index 000000000..ea42b5b00
--- /dev/null
+++ b/mod/groups/views/default/river/group/create.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Group creation river view.
+ */
+
+$object = $vars['item']->getObjectEntity();
+$excerpt = strip_tags($object->description);
+$excerpt = elgg_get_excerpt($excerpt);
+
+echo elgg_view('river/elements/layout', array(
+ 'item' => $vars['item'],
+ 'message' => $excerpt,
+)); \ No newline at end of file
diff --git a/mod/groups/views/default/river/object/groupforumtopic/create.php b/mod/groups/views/default/river/object/groupforumtopic/create.php
new file mode 100644
index 000000000..e7d92bc08
--- /dev/null
+++ b/mod/groups/views/default/river/object/groupforumtopic/create.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Group forum topic create river view.
+ */
+
+$object = $vars['item']->getObjectEntity();
+$excerpt = strip_tags($object->description);
+$excerpt = elgg_get_excerpt($excerpt);
+
+$responses = '';
+if (elgg_is_logged_in() && $object->canAnnotate(0, 'group_topic_post')) {
+ // inline comment form
+ $form_vars = array('id' => "groups-reply-{$object->getGUID()}", 'class' => 'hidden');
+ $body_vars = array('entity' => $object, 'inline' => true);
+ $responses = elgg_view_form('discussion/reply/save', $form_vars, $body_vars);
+}
+
+echo elgg_view('river/elements/layout', array(
+ 'item' => $vars['item'],
+ 'message' => $excerpt,
+ 'responses' => $responses,
+));
diff --git a/mod/groups/views/default/river/relationship/member/create.php b/mod/groups/views/default/river/relationship/member/create.php
new file mode 100644
index 000000000..0afd87e4b
--- /dev/null
+++ b/mod/groups/views/default/river/relationship/member/create.php
@@ -0,0 +1,8 @@
+<?php
+/**
+ * Group join river view.
+ */
+
+echo elgg_view('river/elements/layout', array(
+ 'item' => $vars['item'],
+));
diff --git a/mod/groups/views/default/widgets/a_users_groups/content.php b/mod/groups/views/default/widgets/a_users_groups/content.php
new file mode 100644
index 000000000..fe1a46e39
--- /dev/null
+++ b/mod/groups/views/default/widgets/a_users_groups/content.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Elgg file widget view
+ *
+ * @package ElggFile
+ */
+
+
+$num = $vars['entity']->num_display;
+
+$options = array(
+ 'type' => 'group',
+ 'relationship' => 'member',
+ 'relationship_guid' => $vars['entity']->owner_guid,
+ 'limit' => $num,
+ 'full_view' => FALSE,
+ 'pagination' => FALSE,
+);
+$content = elgg_list_entities_from_relationship($options);
+
+echo $content;
+
+if ($content) {
+ $url = "groups/member/" . elgg_get_page_owner_entity()->username;
+ $more_link = elgg_view('output/url', array(
+ 'href' => $url,
+ 'text' => elgg_echo('groups:more'),
+ 'is_trusted' => true,
+ ));
+ echo "<span class=\"elgg-widget-more\">$more_link</span>";
+} else {
+ echo elgg_echo('groups:none');
+}
diff --git a/mod/groups/views/default/widgets/a_users_groups/edit.php b/mod/groups/views/default/widgets/a_users_groups/edit.php
new file mode 100644
index 000000000..e49a996b7
--- /dev/null
+++ b/mod/groups/views/default/widgets/a_users_groups/edit.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Elgg group widget edit view
+ *
+ * @package ElggGroups
+ */
+
+
+// set default value
+if (!isset($vars['entity']->num_display)) {
+ $vars['entity']->num_display = 4;
+}
+
+$params = array(
+ 'name' => 'params[num_display]',
+ 'value' => $vars['entity']->num_display,
+ 'options' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20),
+);
+$dropdown = elgg_view('input/dropdown', $params);
+
+?>
+<div>
+ <?php echo elgg_echo('groups:widget:num_display'); ?>:
+ <?php echo $dropdown; ?>
+</div>
diff --git a/mod/groups/views/rss/annotation/group_topic_post.php b/mod/groups/views/rss/annotation/group_topic_post.php
new file mode 100644
index 000000000..0d3a40117
--- /dev/null
+++ b/mod/groups/views/rss/annotation/group_topic_post.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * RSS view for a discussion reply
+ *
+ * @uses $vars['annotation']
+ */
+
+$annotation = $vars['annotation'];
+
+$poster = $annotation->getOwnerEntity();
+$poster_name = htmlspecialchars($poster->name, ENT_NOQUOTES, 'UTF-8');
+$pubdate = date('r', $annotation->getTimeCreated());
+$permalink = $annotation->getURL();
+
+$title = elgg_echo('discussion:reply:title', array($poster_name));
+
+$creator = elgg_view('page/components/creator', array('entity' => $annotation));
+$extensions = elgg_view('extensions/item', $vars);
+
+$item = <<<__HTML
+<item>
+ <guid isPermaLink='true'>$permalink</guid>
+ <pubDate>$pubdate</pubDate>
+ <link>$permalink</link>
+ <title><![CDATA[$title]]></title>
+ <description><![CDATA[{$vars['annotation']->value}]]></description>
+ $creator$extensions
+</item>
+
+__HTML;
+
+echo $item;
diff --git a/mod/groups/views/rss/discussion/replies.php b/mod/groups/views/rss/discussion/replies.php
new file mode 100644
index 000000000..419003b21
--- /dev/null
+++ b/mod/groups/views/rss/discussion/replies.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * List replies RSS view
+ *
+ * @uses $vars['entity'] ElggEntity
+ */
+
+$options = array(
+ 'guid' => $vars['entity']->getGUID(),
+ 'annotation_name' => 'group_topic_post',
+);
+echo elgg_list_annotations($options);
diff --git a/mod/groups/views/rss/groups/profile/layout.php b/mod/groups/views/rss/groups/profile/layout.php
new file mode 100644
index 000000000..0dafe78ad
--- /dev/null
+++ b/mod/groups/views/rss/groups/profile/layout.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Group profile RSS view
+ *
+ * Displays a list of the latest content in the group
+ *
+ * @uses $vars['entity'] ElggGroup object
+ */
+
+$entities = elgg_get_config('registered_entities');
+
+if (!empty($entities['object'])) {
+ echo elgg_list_entities(array(
+ 'type' => 'object',
+ 'subtypes' => $entities['object'],
+ 'container_guid' => $vars['entity']->getGUID(),
+ ));
+}
diff --git a/mod/groups/views/rss/object/groupforumtopic.php b/mod/groups/views/rss/object/groupforumtopic.php
new file mode 100644
index 000000000..b2d05d488
--- /dev/null
+++ b/mod/groups/views/rss/object/groupforumtopic.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Elgg groupforumtopic RSS view
+ *
+ * @package ElggGroups
+ */
+
+$title = $vars['entity']->title;
+if (empty($title)) {
+ $title = strip_tags($vars['entity']->description);
+ $title = elgg_get_excerpt($title, 32);
+}
+
+$permalink = htmlspecialchars($vars['entity']->getURL(), ENT_NOQUOTES, 'UTF-8');
+$pubdate = date('r', $vars['entity']->getTimeCreated());
+
+$description = elgg_autop($vars['entity']->description);
+
+$creator = elgg_view('page/components/creator', $vars);
+$georss = elgg_view('page/components/georss', $vars);
+$extension = elgg_view('extensions/item', $vars);
+
+$item = <<<__HTML
+<item>
+ <guid isPermaLink="true">$permalink</guid>
+ <pubDate>$pubdate</pubDate>
+ <link>$permalink</link>
+ <title><![CDATA[$title]]></title>
+ <description><![CDATA[$description]]></description>
+ $creator$georss$extension
+</item>
+
+__HTML;
+
+echo $item;