diff --git a/INSTALL.chat b/INSTALL.chat new file mode 100644 index 0000000..5bcb418 --- /dev/null +++ b/INSTALL.chat @@ -0,0 +1,12 @@ +To configure XMPP/BOSH in Noosfero you need: + +* REST Client - http://github.com/archiloque/rest-client +* SystemTimer - http://ph7spot.com/musings/system-timer +* Pidgin data files - http://www.pidgin.im/ + +# apt-get install librestclient-ruby +# apt-get install libsystemtimer-ruby (depends to do Debian package to this) +# apt-get install pidgin-data + +Take a look at util/chat directory to see samples of config file to configure a +XMPP/BOSH server with ejabberd, postgresql and apache2. diff --git a/app/controllers/application.rb b/app/controllers/application.rb index 7f147a8..2d2fa42 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -116,7 +116,7 @@ class ApplicationController < ActionController::Base def render_not_found(path = nil) @no_design_blocks = true @path ||= request.path - render :template => 'shared/not_found.rhtml', :status => 404 + render :template => 'shared/not_found.rhtml', :status => 404, :layout => get_layout end def render_access_denied(message = nil, title = nil) diff --git a/app/controllers/public/chat_controller.rb b/app/controllers/public/chat_controller.rb new file mode 100644 index 0000000..223f06f --- /dev/null +++ b/app/controllers/public/chat_controller.rb @@ -0,0 +1,56 @@ +class ChatController < PublicController + + before_filter :login_required + before_filter :check_environment_feature + + def start_session + login = current_user.jid + password = current_user.crypted_password + begin + jid, sid, rid = RubyBOSH.initialize_session(login, password, "http://#{environment.default_hostname}/http-bind") + session_data = { :jid => jid, :sid => sid, :rid => rid } + render :text => session_data.to_json, :layout => false, :content_type => 'application/javascript' + rescue + render :action => 'start_session_error', :layout => false, :status => 500 + end + end + + def avatar + person = environment.people.find_by_identifier(params[:id]) + filename, mimetype = profile_icon(person, :minor, true) + data = File.read(File.join(RAILS_ROOT, 'public', filename)) + render :text => data, :layout => false, :content_type => mimetype + expires_in 24.hours + end + + def index + presence = current_user.last_presence_status + if presence.blank? + render :text => '', :layout => 'chat' + elsif presence == 'chat' + render :action => 'auto_connect_online' + else + render :action => 'auto_connect_busy' + end + end + + def update_presence_status + if request.xhr? + unless params[:closing_window] + current_user.update_attribute(:last_presence_status, params[:presence_status]) + end + current_user.update_attribute(:presence_status, params[:presence_status]) + end + render :nothing => true + end + + protected + + def check_environment_feature + unless environment.enabled?('xmpp_chat') + render_not_found + return + end + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index d7437f8..8eb4822 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -421,9 +421,11 @@ module ApplicationHelper image_tag(profile_icon(profile, size), opt ) end - def profile_icon( profile, size=:portrait ) + def profile_icon( profile, size=:portrait, return_mimetype=false ) + filename, mimetype = '', 'image/png' if profile.image - profile.image.public_filename( size ) + filename = profile.image.public_filename( size ) + mimetype = profile.image.content_type else icon = if profile.organization? @@ -435,8 +437,9 @@ module ApplicationHelper else '/images/icons-app/person-'+ size.to_s() +'.png' end - default_or_themed_icon(icon) + filename = default_or_themed_icon(icon) end + return_mimetype ? [filename, mimetype] : filename end def default_or_themed_icon(icon) @@ -940,12 +943,15 @@ module ApplicationHelper end def icon_theme_stylesheet_path - theme_path = "/designs/icons/#{environment.icon_theme}/style.css" - if File.exists?(File.join(RAILS_ROOT, 'public', theme_path)) - theme_path - else - '/designs/icons/default/style.css' + icon_themes = [] + theme_icon_themes = theme_option(:icon_theme) || [] + for icon_theme in theme_icon_themes do + theme_path = "/designs/icons/#{icon_theme}/style.css" + if File.exists?(File.join(RAILS_ROOT, 'public', theme_path)) + icon_themes << theme_path + end end + icon_themes end def page_title @@ -954,6 +960,7 @@ module ApplicationHelper (@topic ? @topic.title + ' - ' : '') + (@section ? @section.title + ' - ' : '') + (@toc ? _('Online Manual') + ' - ' : '') + + (@controller.controller_name == 'chat' ? _('Chat') + ' - ' : '') + environment.name + (@category ? " - #{@category.full_name}" : '') end @@ -1105,4 +1112,23 @@ module ApplicationHelper will_paginate(collection, options) end + def usermenu_from_environment_features + usermenu_html = '' + environment.enabled_features.keys.each do |feature| + file = File.join(@controller.view_paths, 'shared', 'usermenu', "#{feature}.rhtml") + if File.exists?(file) + usermenu_html << render(:file => file, :use_full_path => false) + end + end + usermenu_html + end + + def usermenu_logged_in + (_('Welcome, %s') % link_to('%{login}', '/%{login}', :id => "homepage-link", :title => _('Go to your homepage'))) + + usermenu_from_environment_features + + link_to('' + _('Administration') + '', { :controller => 'admin_panel', :action => 'index' }, :id => "controlpanel", :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') + + link_to('' + _('Control panel') + '', '/myprofile/%{login}', :id => "controlpanel", :title => _("Configure your personal account and content")) + + link_to('' + _('Logout') + '', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) + end + end diff --git a/app/helpers/chat_helper.rb b/app/helpers/chat_helper.rb new file mode 100644 index 0000000..a95cf0b --- /dev/null +++ b/app/helpers/chat_helper.rb @@ -0,0 +1,24 @@ +module ChatHelper + + def user_status_menu(icon_class, status) + links = [ + ['icon-menu-online', _('Online'), 'chat-connect'], + ['icon-menu-busy', _('Busy'), 'chat-busy'], + ['icon-menu-offline', _('Sign out of chat'), 'chat-disconnect'], + ] + content_tag('span', + link_to(content_tag('span', status) + ui_icon('ui-icon-triangle-1-s'), + '#', + :onclick => 'toggleMenu(this); return false', + :class => icon_class + ' simplemenu-trigger' + ) + + content_tag('ul', + links.map{|link| content_tag('li', link_to(link[1], '#', :class => link[0], :id => link[2], 'data-jid' => current_user.jid), :class => 'simplemenu-item') }.join("\n"), + :style => 'display: none; z-index: 100', + :class => 'simplemenu-submenu' + ), + :class => 'user-status' + ) + end + +end diff --git a/app/models/environment.rb b/app/models/environment.rb index ff7dd91..91b31f0 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -111,6 +111,7 @@ class Environment < ActiveRecord::Base 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"), 'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'), 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'), + 'xmpp_chat' => _('XMPP/Jabber based chat'), } end @@ -210,7 +211,6 @@ class Environment < ActiveRecord::Base settings_items :description, :type => String settings_items :category_types, :type => Array, :default => ['Category'] settings_items :enable_ssl - settings_items :icon_theme, :type => String, :default => 'default' settings_items :local_docs, :type => Array, :default => [] settings_items :news_amount_by_folder, :type => Integer, :default => 4 settings_items :help_message_to_add_enterprise, :type => String, :default => '' @@ -255,6 +255,11 @@ class Environment < ActiveRecord::Base end end + def enabled_features + features = self.class.available_features + features.delete_if{ |k, v| !self.enabled?(k) } + end + # returns true if this Environment has terms of use to be # accepted by users before registration. def has_terms_of_use? diff --git a/app/models/person.rb b/app/models/person.rb index b252c8b..cdb20c7 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -31,6 +31,11 @@ class Person < Profile self.user.destroy if self.user end + named_scope :connected, + :select => Profile.qualified_column_names, + :joins => :user, + :conditions => ['presence_status IS NOT NULL AND presence_status != ? AND presence_status != ?', 'offline', ''] + # Sets the identifier for this person. Raises an exception when called on a # existing person (since peoples' identifiers cannot be changed) def identifier=(value) diff --git a/app/models/profile.rb b/app/models/profile.rb index 6a698f3..3855b0a 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -136,6 +136,7 @@ class Profile < ActiveRecord::Base root assets doc + chat ] belongs_to :user diff --git a/app/models/user.rb b/app/models/user.rb index aaff0fa..2e3f4ee 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -214,6 +214,10 @@ class User < ActiveRecord::Base end end + def jid + "#{login}@#{environment.default_hostname}" + end + protected # before filter def encrypt_password diff --git a/app/views/chat/auto_connect_busy.rhtml b/app/views/chat/auto_connect_busy.rhtml new file mode 100644 index 0000000..3d8e3ec --- /dev/null +++ b/app/views/chat/auto_connect_busy.rhtml @@ -0,0 +1,5 @@ + diff --git a/app/views/chat/auto_connect_online.rhtml b/app/views/chat/auto_connect_online.rhtml new file mode 100644 index 0000000..e262146 --- /dev/null +++ b/app/views/chat/auto_connect_online.rhtml @@ -0,0 +1,5 @@ + diff --git a/app/views/chat/start_session_error.rhtml b/app/views/chat/start_session_error.rhtml new file mode 100644 index 0000000..7eb2616 --- /dev/null +++ b/app/views/chat/start_session_error.rhtml @@ -0,0 +1,4 @@ +
+<%= ui_icon('ui-icon-alert') %> +<%= _('Could not connect to chat') %>, ><%= _('try again') %>. +
diff --git a/app/views/layouts/application-ng.rhtml b/app/views/layouts/application-ng.rhtml index 42c97e7..8226d4c 100644 --- a/app/views/layouts/application-ng.rhtml +++ b/app/views/layouts/application-ng.rhtml @@ -24,15 +24,6 @@ " action-"+ @controller.controller_name() +"-"+ @controller.action_name() + " template-"+ ( profile.nil? ? "default" : profile.layout_template ) %>" > - <%= _("Go to the content") %> @@ -43,10 +34,7 @@