diff --git a/doc/app/ActionView.html b/doc/app/ActionView.html new file mode 100644 index 0000000000..3926558742 --- /dev/null +++ b/doc/app/ActionView.html @@ -0,0 +1,95 @@ + + + + + + +module ActionView - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module ActionView +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/ActionView/Base.html b/doc/app/ActionView/Base.html new file mode 100644 index 0000000000..c6ce861bda --- /dev/null +++ b/doc/app/ActionView/Base.html @@ -0,0 +1,113 @@ + + + + + + +class ActionView::Base - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class ActionView::Base +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/ActionView/Helpers.html b/doc/app/ActionView/Helpers.html new file mode 100644 index 0000000000..7887f444c0 --- /dev/null +++ b/doc/app/ActionView/Helpers.html @@ -0,0 +1,95 @@ + + + + + + +module ActionView::Helpers - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module ActionView::Helpers +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/ActionView/Helpers/DynamicForm.html b/doc/app/ActionView/Helpers/DynamicForm.html new file mode 100644 index 0000000000..61ed41ca5e --- /dev/null +++ b/doc/app/ActionView/Helpers/DynamicForm.html @@ -0,0 +1,517 @@ + + + + + + +module ActionView::Helpers::DynamicForm - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module ActionView::Helpers::DynamicForm +

+ +
+ +

The Active Record Helper makes it easier to create forms for records kept +in instance variables. The most far-reaching is the form +method that creates a complete form for all the basic content types of the +record (not associations or aggregations, though). This is a great way of +making the record quickly available for editing, but likely to prove +lackluster for a complicated real-world form. In that case, it's better +to use the input method and the specialized form +methods in classes/ActionView/Helpers/FormHelper.html

+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ error_message_on(object, method, *args) + + click to toggle source + +
+ + +
+ +

Returns a string containing the error message attached to the +method on the object if one exists. This error +message is wrapped in a DIV tag by default or with +:html_tag if specified, which can be extended to include a +:prepend_text and/or :append_text (to properly +explain the error), and a :css_class to style it accordingly. +object should either be the name of an instance variable or +the actual object. The method can be passed in either as a string or a +symbol. As an example, let's say you have a model @post +that has an error message on the title attribute:

+ +
<%= error_message_on "post", "title" %>
+# => <div class="formError">can't be empty</div>
+
+<%= error_message_on @post, :title %>
+# => <div class="formError">can't be empty</div>
+
+<%= error_message_on "post", "title",
+    :prepend_text => "Title simply ",
+    :append_text => " (or it won't work).",
+    :html_tag => "span",
+    :css_class => "inputError" %>
+# => <span class="inputError">Title simply can't be empty (or it won't work).</span>
+ + + + +
+
# File lib/dynamic_form/action_view/helpers/dynamic_form.rb, line 109
+def error_message_on(object, method, *args)
+  options = args.extract_options!
+  unless args.empty?
+    ActiveSupport::Deprecation.warn('error_message_on takes an option hash instead of separate ' +
+      'prepend_text, append_text, html_tag, and css_class arguments', caller)
+
+    options[:prepend_text] = args[0] || ''
+    options[:append_text] = args[1] || ''
+    options[:html_tag] = args[2] || 'div'
+    options[:css_class] = args[3] || 'formError'
+  end
+  options.reverse_merge!(:prepend_text => '', :append_text => '', :html_tag => 'div', :css_class => 'formError')
+
+  object = convert_to_model(object)
+
+  if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
+    (errors = obj.errors[method]).presence
+    content_tag(options[:html_tag],
+      (options[:prepend_text].html_safe << errors.first).safe_concat(options[:append_text]),
+      :class => options[:css_class]
+    )
+  else
+    ''
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ error_messages_for(*params) + + click to toggle source + +
+ + +
+ +

Returns a string with a DIV containing all of the error +messages for the objects located as instance variables by the names given. +If more than one object is specified, the errors for the objects are +displayed in the order that the object names are provided.

+ +

This DIV can be tailored by the following options:

+
  • +

    :header_tag - Used for the header of the error div (default: +“h2”).

    +
  • +

    :id - The id of the error div (default: “errorExplanation”).

    +
  • +

    :class - The class of the error div (default: +“errorExplanation”).

    +
  • +

    :object - The object (or array of objects) for which to +display errors, if you need to escape the instance variable convention.

    +
  • +

    :object_name - The object name to use in the header, or any +text that you prefer. If :object_name is not set, the name of +the first object will be used.

    +
  • +

    :header_message - The message in the header of the error div. +Pass nil or an empty string to avoid the header message +altogether. (Default: “X errors prohibited this object from being saved”).

    +
  • +

    :message - The explanation message after the header message +and before the error list. Pass nil or an empty string to +avoid the explanation message altogether. (Default: “There were problems +with the following fields:”).

    +
+ +

To specify the display for one object, you simply provide its name as a +parameter. For example, for the @user model:

+ +
error_messages_for 'user'
+
+ +

You can also supply an object:

+ +
error_messages_for @user
+
+ +

This will use the last part of the model name in the presentation. For +instance, if this is a MyKlass::User object, this will use “user” as the +name in the String. This is taken from MyKlass::User.model_name.human, +which can be overridden.

+ +

To specify more than one object, you simply list them; optionally, you can +add an extra :object_name parameter, which will be the name +used in the header message:

+ +
error_messages_for 'user_common', 'user', :object_name => 'user'
+
+ +

You can also use a number of objects, which will have the same naming +semantics as a single object.

+ +
error_messages_for @user, @post
+
+ +

If the objects cannot be located as instance variables, you can add an +extra :object parameter which gives the actual object (or +array of objects to use):

+ +
error_messages_for 'user', :object => @question.user
+
+ +

NOTE: This is a pre-packaged presentation of the errors with embedded +strings and a certain HTML structure. If what you need is significantly +different from the default presentation, it makes plenty of sense to access +the object.errors instance yourself and set it up. View the +source of this method to see how easy it is.

+ + + + +
+
# File lib/dynamic_form/action_view/helpers/dynamic_form.rb, line 186
+def error_messages_for(*params)
+  options = params.extract_options!.symbolize_keys
+
+  objects = Array.wrap(options.delete(:object) || params).map do |object|
+    object = instance_variable_get("@#{object}") unless object.respond_to?(:to_model)
+    object = convert_to_model(object)
+
+    if object.class.respond_to?(:model_name)
+      options[:object_name] ||= object.class.model_name.human.downcase
+    end
+
+    object
+  end
+
+  objects.compact!
+  count = objects.inject(0) {|sum, object| sum + object.errors.count }
+
+  unless count.zero?
+    html = {}
+    [:id, :class].each do |key|
+      if options.include?(key)
+        value = options[key]
+        html[key] = value unless value.blank?
+      else
+        html[key] = 'errorExplanation'
+      end
+    end
+    options[:object_name] ||= params.first
+
+    I18n.with_options :locale => options[:locale], :scope => [:errors, :template] do |locale|
+      header_message = if options.include?(:header_message)
+        options[:header_message]
+      else
+        locale.t :header, :count => count, :model => options[:object_name].to_s.gsub('_', ' ')
+      end
+
+      message = options.include?(:message) ? options[:message] : locale.t(:body)
+
+      error_messages = objects.sum do |object|
+        object.errors.full_messages.map do |msg|
+          content_tag(:li, msg)
+        end
+      end.join.html_safe
+
+      contents = ''
+      contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
+      contents << content_tag(:p, message) unless message.blank?
+      contents << content_tag(:ul, error_messages)
+
+      content_tag(:div, contents.html_safe, html)
+    end
+  else
+    ''
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ form(record_name, options = {}) { |contents| ... } + + click to toggle source + +
+ + +
+ +

Returns an entire form with all needed input tags for a specified Active +Record object. For example, if @post has attributes named +title of type VARCHAR and body of +type TEXT then

+ +
form("post")
+
+ +

would yield a form like the following (modulus formatting):

+ +
<form action='/posts/create' method='post'>
+  <p>
+    <label for="post_title">Title</label><br />
+    <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
+  </p>
+  <p>
+    <label for="post_body">Body</label><br />
+    <textarea cols="40" id="post_body" name="post[body]" rows="20"></textarea>
+  </p>
+  <input name="commit" type="submit" value="Create" />
+</form>
+ +

It's possible to specialize the form builder by using a different +action name and by supplying another block renderer. For example, if +@entry has an attribute message of type +VARCHAR then

+ +
form("entry",
+  :action => "sign",
+  :input_block => Proc.new { |record, column|
+    "#{column.human_name}: #{input(record, column.name)}<br />"
+})
+
+ +

would yield a form like the following (modulus formatting):

+ +
<form action="/entries/sign" method="post">
+  Message:
+  <input id="entry_message" name="entry[message]" size="30" type="text" /><br />
+  <input name="commit" type="submit" value="Sign" />
+</form>
+ +

It's also possible to add additional content to the form by giving it a +block, such as:

+ +
form("entry", :action => "sign") do |form|
+  form << content_tag("b", "Department")
+  form << collection_select("department", "id", @departments, "id", "name")
+end
+
+ +

The following options are available:

+
  • +

    :action - The action used when submitting the form (default: +create if a new record, otherwise update).

    +
  • +

    :input_block - Specialize the output using a different block, +see above.

    +
  • +

    :method - The method used when submitting the form (default: +post).

    +
  • +

    :multipart - Whether to change the enctype of the form to +“multipart/form-data”, used when uploading a file (default: +false).

    +
  • +

    :submit_value - The text of the submit button (default: +“Create” if a new record, otherwise “Update”).

    +
+ + + + +
+
# File lib/dynamic_form/action_view/helpers/dynamic_form.rb, line 72
+def form(record_name, options = {})
+  record = instance_variable_get("@#{record_name}")
+  record = convert_to_model(record)
+
+  options = options.symbolize_keys
+  options[:action] ||= record.persisted? ? "update" : "create"
+  action = url_for(:action => options[:action], :id => record)
+
+  submit_value = options[:submit_value] || options[:action].gsub(/[^\w]/, '').capitalize
+
+  contents = form_tag({:action => action}, :method =>(options[:method] || 'post'), :enctype => options[:multipart] ? 'multipart/form-data': nil)
+  contents.safe_concat hidden_field(record_name, :id) if record.persisted?
+  contents.safe_concat all_input_tags(record, record_name, options)
+  yield contents if block_given?
+  contents.safe_concat submit_tag(submit_value)
+  contents.safe_concat('</form>')
+end
+
+ +
+ + + + +
+ + +
+ +
+ input(record_name, method, options = {}) + + click to toggle source + +
+ + +
+ +

Returns a default input tag for the type of object returned by the method. +For example, if @post has an attribute title +mapped to a VARCHAR column that holds “Hello World”:

+ +
input("post", "title")
+# => <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
+
+ + + + +
+
# File lib/dynamic_form/action_view/helpers/dynamic_form.rb, line 18
+def input(record_name, method, options = {})
+  InstanceTag.new(record_name, method, self).to_tag(options)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/ActionView/Helpers/DynamicForm/FormBuilderMethods.html b/doc/app/ActionView/Helpers/DynamicForm/FormBuilderMethods.html new file mode 100644 index 0000000000..0507423d2f --- /dev/null +++ b/doc/app/ActionView/Helpers/DynamicForm/FormBuilderMethods.html @@ -0,0 +1,181 @@ + + + + + + +module ActionView::Helpers::DynamicForm::FormBuilderMethods - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module ActionView::Helpers::DynamicForm::FormBuilderMethods +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ error_message_on(method, *args) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/dynamic_form/action_view/helpers/dynamic_form.rb, line 280
+def error_message_on(method, *args)
+  @template.error_message_on(@object || @object_name, method, *args)
+end
+
+ +
+ + + + +
+ + +
+ +
+ error_messages(options = {}) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/dynamic_form/action_view/helpers/dynamic_form.rb, line 284
+def error_messages(options = {})
+  @template.error_messages_for(@object_name, objectify_options(options))
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/ActionView/Helpers/DynamicForm/InstanceTagMethods.html b/doc/app/ActionView/Helpers/DynamicForm/InstanceTagMethods.html new file mode 100644 index 0000000000..c9adb15289 --- /dev/null +++ b/doc/app/ActionView/Helpers/DynamicForm/InstanceTagMethods.html @@ -0,0 +1,197 @@ + + + + + + +module ActionView::Helpers::DynamicForm::InstanceTagMethods - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module ActionView::Helpers::DynamicForm::InstanceTagMethods +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ column_type() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/dynamic_form/action_view/helpers/dynamic_form.rb, line 274
+def column_type
+  object.send(:column_for_attribute, @method_name).type
+end
+
+ +
+ + + + +
+ + +
+ +
+ to_tag(options = {}) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/dynamic_form/action_view/helpers/dynamic_form.rb, line 254
+def to_tag(options = {})
+  case column_type
+    when :string
+      field_type = @method_name.include?("password") ? "password" : "text"
+      to_input_field_tag(field_type, options)
+    when :text
+      to_text_area_tag(options)
+    when :integer, :float, :decimal
+      to_input_field_tag("text", options)
+    when :date
+      to_date_select_tag(options)
+    when :datetime, :timestamp
+      to_datetime_select_tag(options)
+    when :time
+      to_time_select_tag(options)
+    when :boolean
+      to_boolean_select_tag(options)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/ActionView/Helpers/FormBuilder.html b/doc/app/ActionView/Helpers/FormBuilder.html new file mode 100644 index 0000000000..0151c94333 --- /dev/null +++ b/doc/app/ActionView/Helpers/FormBuilder.html @@ -0,0 +1,113 @@ + + + + + + +class ActionView::Helpers::FormBuilder - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class ActionView::Helpers::FormBuilder +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/ActionView/Helpers/InstanceTag.html b/doc/app/ActionView/Helpers/InstanceTag.html new file mode 100644 index 0000000000..df1d3f3b0d --- /dev/null +++ b/doc/app/ActionView/Helpers/InstanceTag.html @@ -0,0 +1,113 @@ + + + + + + +class ActionView::Helpers::InstanceTag - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class ActionView::Helpers::InstanceTag +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/ActiveRecord.html b/doc/app/ActiveRecord.html new file mode 100644 index 0000000000..949508e924 --- /dev/null +++ b/doc/app/ActiveRecord.html @@ -0,0 +1,95 @@ + + + + + + +module ActiveRecord - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module ActiveRecord +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/AdminController.html b/doc/app/AdminController.html new file mode 100644 index 0000000000..b2d1893fa2 --- /dev/null +++ b/doc/app/AdminController.html @@ -0,0 +1,1003 @@ + + + + + + +class AdminController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class AdminController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ ban() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 220
+def ban
+  user = DrupalUser.find params[:id]
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    user.ban
+    flash[:notice] = 'The user has been banned.'
+  else
+    flash[:error] = 'Only moderators can ban other users.'
+  end
+  redirect_to '/profile/' + user.name + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ batch() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 251
+def batch
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    nodes = 0
+    users = []
+    params[:ids].split(',').uniq.each do |nid|
+      node = Node.find nid
+      node.spam
+      nodes += 1
+      user = node.author
+      user.ban
+      users << user.id
+    end
+    flash[:notice] = nodes.to_s + ' nodes spammed and ' + users.length.to_s + ' users banned.'
+    redirect_to '/spam/wiki'
+  else
+    flash[:error] = 'Only admins can batch moderate.'
+    redirect_to '/dashboard'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ demote_basic() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 32
+def demote_basic
+  @user = User.find params[:id]
+  unless @user.nil?
+    if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+      @user.role = 'basic'
+      @user.save({})
+      flash[:notice] = "User '<a href='/profile/" + @user.username + "'>" + @user.username + "</a>' is no longer a moderator."
+    else
+      flash[:error] = 'Only admins and moderators can demote other users.'
+    end
+  end
+  redirect_to '/profile/' + @user.username + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ mark_spam() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 103
+def mark_spam
+  @node = Node.find params[:id]
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    if @node.status == 1 || @node.status == 4
+      @node.spam
+      @node.author.ban
+      AdminMailer.notify_moderators_of_spam(@node, current_user)
+      flash[:notice] = "Item marked as spam and author banned. You can undo this on the <a href='/spam'>spam moderation page</a>."
+      redirect_to '/dashboard'
+    else
+      flash[:notice] = "Item already marked as spam and author banned. You can undo this on the <a href='/spam'>spam moderation page</a>."
+      redirect_to '/dashboard'
+    end
+  else
+    flash[:error] = 'Only moderators can moderate posts.'
+    if @node.has_power_tag('question')
+      redirect_to @node.path(:question)
+    else
+      redirect_to @node.path
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ mark_spam_revision() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 159
+def mark_spam_revision
+  @revision = Revision.find_by(vid: params[:vid])
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    if @revision.status == 1
+      @revision.spam
+      @revision.author.ban
+      flash[:notice] = "Item marked as spam and author banned. You can undo this on the <a href='/spam/revisions'>spam moderation page</a>."
+      redirect_to '/wiki/revisions/' + @revision.node.slug_from_path + '?_=' + Time.now.to_i.to_s
+    else
+      flash[:notice] = "Item already marked as spam and author banned. You can undo this on the <a href='/spam/revisions'>spam moderation page</a>."
+      redirect_to '/dashboard'
+    end
+  else
+    flash[:error] = 'Only moderators can moderate posts.'
+    if @node.has_power_tag('question')
+      redirect_to @node.path(:question)
+    else
+      redirect_to @node.path
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ migrate() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 271
+def migrate
+  if current_user && current_user.role == 'admin'
+    du = DrupalUser.find params[:id]
+    if du.user
+      flash[:error] = 'The user has already been migrated.'
+    else
+      if du.migrate
+        flash[:notice] = 'The user was migrated! Enthusiasm!'
+      else
+        flash[:error] = 'The user could not be migrated.'
+      end
+    end
+  else
+    flash[:error] = 'Only admins can migrate users.'
+  end
+  redirect_to '/profile/' + du.name
+end
+
+ +
+ + + + +
+ + +
+ +
+ moderate() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 198
+def moderate
+  user = DrupalUser.find params[:id]
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    user.moderate
+    flash[:notice] = 'The user has been moderated.'
+  else
+    flash[:error] = 'Only moderators can moderate other users.'
+  end
+  redirect_to '/profile/' + user.name + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ promote_admin() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 4
+def promote_admin
+  @user = User.find params[:id]
+  unless @user.nil?
+    if current_user && current_user.role == 'admin'
+      @user.role = 'admin'
+      @user.save({})
+      flash[:notice] = "User '<a href='/profile/" + @user.username + "'>" + @user.username + "</a>' is now an admin."
+    else
+      flash[:error] = 'Only admins can promote other users to admins.'
+    end
+  end
+  redirect_to '/profile/' + @user.username + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ promote_moderator() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 18
+def promote_moderator
+  @user = User.find params[:id]
+  unless @user.nil?
+    if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+      @user.role = 'moderator'
+      @user.save({})
+      flash[:notice] = "User '<a href='/profile/" + @user.username + "'>" + @user.username + "</a>' is now a moderator."
+    else
+      flash[:error] = 'Only moderators can promote other users.'
+    end
+  end
+  redirect_to '/profile/' + @user.username + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ publish() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 126
+def publish
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    @node = Node.find params[:id]
+    if @node.status == 1
+      flash[:notice] = 'Item already published.'
+    else
+      first_timer_post = (@node.status == 4)
+      @node.publish
+      @node.author.unban
+      if first_timer_post
+        AdminMailer.notify_author_of_approval(@node, current_user)
+        AdminMailer.notify_moderators_of_approval(@node, current_user)
+        SubscriptionMailer.notify_node_creation(@node)
+        if @node.has_power_tag('question')
+          flash[:notice] = "Question approved and published after #{time_ago_in_words(@node.created_at)} in moderation. Now reach out to the new community member; thank them, just say hello, or help them revise/format their post in the comments."
+        else
+          flash[:notice] = "Post approved and published after #{time_ago_in_words(@node.created_at)} in moderation. Now reach out to the new community member; thank them, just say hello, or help them revise/format their post in the comments."
+        end
+      else
+        flash[:notice] = 'Item published.'
+      end
+    end
+    if @node.has_power_tag('question')
+      redirect_to @node.path(:question)
+    else
+      redirect_to @node.path
+    end
+  else
+    flash[:error] = 'Only moderators can publish posts.'
+    redirect_to '/dashboard'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ publish_revision() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 181
+def publish_revision
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    @revision = Revision.find params[:vid]
+    @revision.publish
+    @revision.author.unban
+    flash[:notice] = 'Item published.'
+    if @revision.parent.has_power_tag('question')
+      redirect_to @revision.parent.path(:question)
+    else
+      redirect_to @revision.parent.path
+    end
+  else
+    flash[:error] = 'Only moderators can publish posts.'
+    redirect_to '/dashboard'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ queue() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 289
+def queue
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    @notes = Node.where(status: 4)
+                 .paginate(page: params[:page])
+    flash[:warning] = "These are notes requiring moderation. <a href='/wiki/moderation'>Community moderators</a> may approve or reject them."
+    render template: 'notes/index'
+  else
+    flash[:error] = 'Only moderators and admins can see the moderation queue.'
+    redirect_to '/dashboard'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ reset_user_password() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 46
+def reset_user_password
+  if current_user && current_user.role == 'admin'
+    user = User.find(params[:id])
+    if user
+      key = user.generate_reset_key
+      user.save({})
+      # send key to user email
+      PasswordResetMailer.reset_notify(user, key) unless user.nil? # respond the same to both successes and failures; security
+    end
+
+    flash[:notice] = "#{user.name} should receive an email with instructions on how to reset their password. If they do not, please double check that they are using the email they registered with." 
+    redirect_to "/profile/" + user.name
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ spam() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 76
+def spam
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    @nodes = Node.paginate(page: params[:page])
+                 .order('nid DESC')
+    @nodes = if params[:type] == 'wiki'
+               @nodes.where(type: 'page', status: 1)
+             else
+               @nodes.where(status: 0)
+             end
+  else
+    flash[:error] = 'Only moderators can moderate posts.'
+    redirect_to '/dashboard'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ spam_revisions() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 91
+def spam_revisions
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    @revisions = Revision.paginate(page: params[:page])
+                         .order('timestamp DESC')
+                         .where(status: 0)
+    render template: 'admin/spam'
+  else
+    flash[:error] = 'Only moderators can moderate revisions.'
+    redirect_to '/dashboard'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ unban() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 231
+def unban
+  user = DrupalUser.find params[:id]
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    user.unban
+    flash[:notice] = 'The user has been unbanned.'
+  else
+    flash[:error] = 'Only moderators can unban other users.'
+  end
+  redirect_to '/profile/' + user.name + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ unmoderate() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 209
+def unmoderate
+  user = DrupalUser.find params[:id]
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    user.unmoderate
+    flash[:notice] = 'The user has been unmoderated.'
+  else
+    flash[:error] = 'Only moderators can unmoderate other users.'
+  end
+  redirect_to '/profile/' + user.name + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ useremail() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 62
+def useremail
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    if params[:address]
+      # address was submitted. find the username(s) and return.
+      @address = params[:address]
+      @users = User.where(email: params[:address])
+               .where(status: [1,4])
+    end
+  else
+    # unauthorized. instead of return ugly 403, just send somewhere else
+    redirect_to '/dashboard'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ users() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/admin_controller.rb, line 242
+def users
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    @users = DrupalUser.order('uid DESC').limit(200)
+  else
+    flash[:error] = 'Only moderators can moderate other users.'
+    redirect_to '/dashboard'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AdminHelper.html b/doc/app/AdminHelper.html new file mode 100644 index 0000000000..afbd485dc4 --- /dev/null +++ b/doc/app/AdminHelper.html @@ -0,0 +1,95 @@ + + + + + + +module AdminHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module AdminHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/AdminMailer.html b/doc/app/AdminMailer.html new file mode 100644 index 0000000000..c027cdac7f --- /dev/null +++ b/doc/app/AdminMailer.html @@ -0,0 +1,307 @@ + + + + + + +class AdminMailer - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class AdminMailer +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ notify_author_of_approval(node, moderator) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/admin_mailer.rb, line 19
+def notify_author_of_approval(node, moderator)
+  subject = '[Public Lab] Your post was approved!'
+  @author = node.author
+  @moderator = moderator
+  @node = node
+  @footer = feature('email-footer')
+  mail(to: @author.mail, subject: subject).deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_moderators_of_approval(node, moderator) + + click to toggle source + +
+ + +
+ +

Will this further bait spammers? If we don't, will non-spammers whose +posts were moderated get confused? Should: show explanation/appeal process +to authors who visit again Should: prompt moderators to reach out if +it's not spam, but a guidelines violation def +notify_author_of_spam(node) end

+ + + + +
+
# File app/mailers/admin_mailer.rb, line 35
+def notify_moderators_of_approval(node, moderator)
+  subject = '[New Public Lab poster needs moderation] ' + node.title
+  @author = node.author
+  @moderator = moderator
+  @node = node
+  @footer = feature('email-footer')
+  moderators = User.where(role: %w[moderator admin]).collect(&:email)
+  mail(
+    to: "moderators@#{ActionMailer::Base.default_url_options[:host]}",
+    bcc: moderators,
+    subject: subject
+  ).deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_moderators_of_spam(node, moderator) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/admin_mailer.rb, line 49
+def notify_moderators_of_spam(node, moderator)
+  subject = '[New Public Lab poster needs moderation] ' + node.title
+  @author = node.author
+  @moderator = moderator
+  @node = node
+  @footer = feature('email-footer')
+  moderators = User.where(role: %w[moderator admin]).collect(&:email)
+  mail(
+    to: "moderators@#{ActionMailer::Base.default_url_options[:host]}",
+    bcc: moderators,
+    subject: subject
+  ).deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_node_moderators(node) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/admin_mailer.rb, line 6
+def notify_node_moderators(node)
+  subject = '[New Public Lab poster needs moderation] ' + node.title
+  @node = node
+  @user = node.author.user
+  @footer = feature('email-footer')
+  moderators = User.where(role: %w[moderator admin]).collect(&:email)
+  mail(
+    to: "moderators@#{ActionMailer::Base.default_url_options[:host]}",
+    bcc: moderators,
+    subject: subject
+  ).deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/Answer.html b/doc/app/Answer.html new file mode 100644 index 0000000000..24541be77f --- /dev/null +++ b/doc/app/Answer.html @@ -0,0 +1,256 @@ + + + + + + +class Answer - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Answer +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ answer_notify(current_user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/answer.rb, line 29
+def answer_notify(current_user)
+  # notify question author
+  if current_user.uid != node.author.uid
+    AnswerMailer.notify_question_author(node.author, self).deliver
+  end
+  users_with_everything_tag = Tag.followers('everything') 
+  uids = (node.answers.collect(&:uid) + node.likers.collect(&:uid) + users_with_everything_tag.collect(&:uid)).uniq
+  # notify other answer authors and users who liked the question
+  DrupalUser.where('uid IN (?)', uids).each do |user|
+    if (user.uid != current_user.uid) && (user.uid != node.author.uid)
+      AnswerMailer.notify_answer_likers_author(user.user, self).deliver
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ body() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/answer.rb, line 13
+def body
+  finder = content.gsub(Callouts.const_get(:FINDER), Callouts.const_get(:PRETTYLINKMD))
+  finder = finder.gsub(Callouts.const_get(:HASHTAGNUMBER), Callouts.const_get(:NODELINKMD)) 
+  finder = finder.gsub(Callouts.const_get(:HASHTAG), Callouts.const_get(:HASHLINKMD))  
+end
+
+ +
+ + + + +
+ + +
+ +
+ likers() + + click to toggle source + +
+ + +
+ +

users who like this answer

+ + + + +
+
# File app/models/answer.rb, line 20
+def likers
+  answer_selections
+    .joins(:drupal_user)
+    .references(:users)
+    .where(liking: true)
+    .where('users.status = ?', 1)
+    .collect(&:user)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AnswerLikeController.html b/doc/app/AnswerLikeController.html new file mode 100644 index 0000000000..3be06acecb --- /dev/null +++ b/doc/app/AnswerLikeController.html @@ -0,0 +1,199 @@ + + + + + + +class AnswerLikeController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class AnswerLikeController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ likes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/answer_like_controller.rb, line 8
+def likes
+  @answer = Answer.find(params[:aid])
+  if @answer.liked_by(current_user.uid)
+    AnswerSelection.set_likes(current_user.uid, @answer.id, false)
+  else
+    AnswerSelection.set_likes(current_user.uid, @answer.id, true)
+    user = User.find(current_user.uid)
+    AnswerMailer.notify_answer_like(user, @answer).deliver
+  end
+  @answer.reload
+  respond_to do |format|
+    format.js {}
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ show() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/answer_like_controller.rb, line 4
+def show
+  render json: Answer.find(params[:id]).cached_likes
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AnswerMailer.html b/doc/app/AnswerMailer.html new file mode 100644 index 0000000000..ff26b7a500 --- /dev/null +++ b/doc/app/AnswerMailer.html @@ -0,0 +1,284 @@ + + + + + + +class AnswerMailer - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class AnswerMailer +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ notify_answer_accept(user, answer) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/answer_mailer.rb, line 22
+def notify_answer_accept(user, answer)
+  @user = user
+  @answer = answer
+  @footer = feature('email-footer')
+  mail(to: @user.email, subject: '[PublicLab] Your answer has been accepted')
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_answer_like(user, answer) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/answer_mailer.rb, line 29
+def notify_answer_like(user, answer)
+  subject = "[PublicLab] #{user.username} liked your answer to: " + answer.node.title
+  @user = user
+  @answer = answer
+  @footer = feature('email-footer')
+  mail(to: @answer.author.email, subject: subject)
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_answer_likers_author(user, answer) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/answer_mailer.rb, line 14
+def notify_answer_likers_author(user, answer)
+  subject = '[PublicLab] New answer to Question: ' + answer.node.title
+  @user = user
+  @answer = answer
+  @footer = feature('email-footer')
+  mail(to: @user.email, subject: subject)
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_question_author(user, answer) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/answer_mailer.rb, line 6
+def notify_question_author(user, answer)
+  subject = '[PLab] Question: ' + answer.node.title.truncate(30,omission: '...?') + ' An answer has been posted on Public Lab'
+  @user = user
+  @answer = answer
+  @footer = feature('email-footer')
+  mail(to: @user.email, subject: subject)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AnswerSelection.html b/doc/app/AnswerSelection.html new file mode 100644 index 0000000000..475125235c --- /dev/null +++ b/doc/app/AnswerSelection.html @@ -0,0 +1,208 @@ + + + + + + +class AnswerSelection - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class AnswerSelection +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ set_likes(uid, aid, value) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/answer_selection.rb, line 11
+def self.set_likes(uid, aid, value)
+  like = where(user_id: uid, aid: aid).first_or_create
+  like.liking = value
+  if like.liking_changed?
+    answer = Answer.find(aid)
+    if like.liking
+      answer.cached_likes += 1
+    else
+      answer.cached_likes -= 1
+    end
+    like.save
+    answer.save
+  end
+  like.liking
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ user() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/answer_selection.rb, line 7
+def user
+  User.find_by(username: DrupalUser.find_by(uid: user_id).name)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AnswersController.html b/doc/app/AnswersController.html new file mode 100644 index 0000000000..03030a3e52 --- /dev/null +++ b/doc/app/AnswersController.html @@ -0,0 +1,316 @@ + + + + + + +class AnswersController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class AnswersController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ accept() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/answers_controller.rb, line 57
+def accept
+  @answer = Answer.find(params[:id])
+
+  if (current_user.role == "admin" || current_user.role == "moderator" || current_user.uid == @answer.node.uid)
+    respond_to do |format|
+      if @answer.accepted
+        @answer.accepted = false
+        @answer.save
+      else
+        @answer.accepted = true
+        @answer.save
+        AnswerMailer.notify_answer_accept(@answer.author, @answer).deliver
+      end
+      @answer.reload
+      format.js
+    end
+  else
+    render text: "Answer couldn't be accepted"
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/answers_controller.rb, line 4
+def create
+  @node = Node.find(params[:nid])
+  @answer = Answer.new(
+    nid: @node.id,
+    uid: current_user.uid,
+    content: params[:body]
+  )
+  respond_to do |format|
+    if current_user && @answer.save
+      @answer.answer_notify(current_user)
+      format.html { redirect_to @node.path(:question), notice: 'Answer successfully posted' }
+      format.js {}
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/answers_controller.rb, line 37
+def delete
+  @answer = Answer.find(params[:id])
+  if current_user.uid == @answer.node.uid ||
+     @answer.uid == current_user.uid ||
+     current_user.role == 'admin' ||
+     current_user.role == 'moderator'
+    respond_to do |format|
+      if @answer.delete
+        format.html { redirect_to @answer.node.path(:question), notice: 'Answer deleted' }
+        format.js
+      else
+        flash[:error] = "The answer couldn't be deleted"
+        redirect_to @answer.node.path(:question)
+      end
+    end
+  else
+    prompt_login 'Only the answer or question author can delete this answer'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ update() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/answers_controller.rb, line 20
+def update
+  @answer = Answer.find(params[:id])
+  if @answer.uid == current_user.uid
+    @answer.content = params[:body]
+    if @answer.save
+      flash[:notice] = 'Answer updated'
+      redirect_to @answer.node.path(:question)
+    else
+      flash[:error] = "Answer couldn't be updated"
+      redirect_to @answer.node.path(:question)
+    end
+  else
+    flash[:error] = 'Only the author of the answer can edit it.'
+    redirect_to @answer.node.path(:question)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/ApplicationController.html b/doc/app/ApplicationController.html new file mode 100644 index 0000000000..a56ddf41d0 --- /dev/null +++ b/doc/app/ApplicationController.html @@ -0,0 +1,102 @@ + + + + + + +class ApplicationController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class ApplicationController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/ApplicationHelper.html b/doc/app/ApplicationHelper.html new file mode 100644 index 0000000000..87e355ba7b --- /dev/null +++ b/doc/app/ApplicationHelper.html @@ -0,0 +1,312 @@ + + + + + + +module ApplicationHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module ApplicationHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ feature(title) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/helpers/application_helper.rb, line 15
+def feature(title)
+  features = Node.where(type: 'feature', title: title)
+  if !features.empty?
+    return features.last.body.to_s.html_safe
+  else
+    ''
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ insert_extras(body) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/helpers/application_helper.rb, line 30
+def insert_extras(body)
+  body = NodeShared.notes_grid(body)
+  body = NodeShared.questions_grid(body)
+  body = NodeShared.activities_grid(body)
+  body = NodeShared.upgrades_grid(body)
+  body = NodeShared.notes_map(body)
+  body = NodeShared.notes_map_by_tag(body)
+  body = NodeShared.people_grid(body)
+  body = NodeShared.people_map(body)
+  body = NodeShared.graph_grid(body)
+  body = NodeShared.wikis_grid(body)
+  body
+end
+
+ +
+ + + + +
+ + +
+ +
+ locale_name_pairs() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/helpers/application_helper.rb, line 24
+def locale_name_pairs
+  I18n.available_locales.map do |locale|
+    [I18n.t('language', locale: locale), locale]
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ logged_in_as(roles) + + click to toggle source + +
+ + +
+ +

returns true if user is logged in and has any of the roles given, as +['admin','moderator']

+ + + + +
+
# File app/helpers/application_helper.rb, line 3
+def logged_in_as(roles)
+  if current_user
+    has_valid_role = false
+    roles.each do |role|
+      has_valid_role = true if current_user.role == role
+    end
+    has_valid_role
+  else
+    false
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ render_map(lat, lon, items) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/helpers/application_helper.rb, line 44
+def render_map(lat, lon, items)
+  render partial: 'map/leaflet', locals: { lat: lat, lon: lon, items: items }
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/Authlogic.html b/doc/app/Authlogic.html new file mode 100644 index 0000000000..65a17fe88c --- /dev/null +++ b/doc/app/Authlogic.html @@ -0,0 +1,95 @@ + + + + + + +module Authlogic - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module Authlogic +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Authlogic/Session.html b/doc/app/Authlogic/Session.html new file mode 100644 index 0000000000..f12fd6bed7 --- /dev/null +++ b/doc/app/Authlogic/Session.html @@ -0,0 +1,95 @@ + + + + + + +module Authlogic::Session - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module Authlogic::Session +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/AuthlogicOpenid.html b/doc/app/AuthlogicOpenid.html new file mode 100644 index 0000000000..55004bc980 --- /dev/null +++ b/doc/app/AuthlogicOpenid.html @@ -0,0 +1,100 @@ + + + + + + +module AuthlogicOpenid - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module AuthlogicOpenid +

+ +
+ +

This module is responsible for adding OpenID functionality to Authlogic. Checkout the README for more info and please see the sub +modules for detailed documentation.

+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/AuthlogicOpenid/ActsAsAuthentic.html b/doc/app/AuthlogicOpenid/ActsAsAuthentic.html new file mode 100644 index 0000000000..a8cb96393b --- /dev/null +++ b/doc/app/AuthlogicOpenid/ActsAsAuthentic.html @@ -0,0 +1,165 @@ + + + + + + +module AuthlogicOpenid::ActsAsAuthentic - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module AuthlogicOpenid::ActsAsAuthentic +

+ +
+ +

This module is responsible for adding in the OpenID functionality to your +models. It hooks itself into the acts_as_authentic method provided by Authlogic.

+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ included(klass) + + click to toggle source + +
+ + +
+ +

Adds in the neccesary modules for acts_as_authentic to include and also +disabled password validation if OpenID is being used.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb, line 9
+def self.included(klass)
+  klass.class_eval do
+    extend Config
+    add_acts_as_authentic_module(Methods, :prepend)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AuthlogicOpenid/ActsAsAuthentic/Config.html b/doc/app/AuthlogicOpenid/ActsAsAuthentic/Config.html new file mode 100644 index 0000000000..e10563e281 --- /dev/null +++ b/doc/app/AuthlogicOpenid/ActsAsAuthentic/Config.html @@ -0,0 +1,266 @@ + + + + + + +module AuthlogicOpenid::ActsAsAuthentic::Config - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module AuthlogicOpenid::ActsAsAuthentic::Config +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ openid_optional_fields(value = nil) + + click to toggle source + +
+ + +
+ +

Same as required_fields, but optional instead.

+
  • +

    Default: []

    +
  • +

    Accepts: Array of symbols

    +
+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb, line 34
+def openid_optional_fields(value = nil)
+  rw_config(:openid_optional_fields, value, [])
+end
+
+ +
+ + +
+ Also aliased as: openid_optional_fields= +
+ + + +
+ + +
+ +
+ openid_optional_fields=(value = nil) + +
+ + +
+ + + + + + +
+ + + + +
+ Alias for: openid_optional_fields +
+ +
+ + +
+ +
+ openid_required_fields(value = nil) + + click to toggle source + +
+ + +
+ +

Some OpenID providers support a lightweight profile exchange protocol, for +those that do, you can require certain fields. This is convenient for new +registrations, as it will basically fill out the fields in the form for +them, so they don't have to re-type information already stored with +their OpenID account.

+ +

For more info and what fields you can use see: openid.net/specs/openid-simple-registration-extension-1_0.html

+
  • +

    Default: []

    +
  • +

    Accepts: Array of symbols

    +
+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb, line 25
+def openid_required_fields(value = nil)
+  rw_config(:openid_required_fields, value, [])
+end
+
+ +
+ + +
+ Also aliased as: openid_required_fields= +
+ + + +
+ + +
+ +
+ openid_required_fields=(value = nil) + +
+ + +
+ + + + + + +
+ + + + +
+ Alias for: openid_required_fields +
+ +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AuthlogicOpenid/ActsAsAuthentic/Methods.html b/doc/app/AuthlogicOpenid/ActsAsAuthentic/Methods.html new file mode 100644 index 0000000000..1ed02d51d6 --- /dev/null +++ b/doc/app/AuthlogicOpenid/ActsAsAuthentic/Methods.html @@ -0,0 +1,402 @@ + + + + + + +module AuthlogicOpenid::ActsAsAuthentic::Methods - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module AuthlogicOpenid::ActsAsAuthentic::Methods +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ included(klass) + + click to toggle source + +
+ + +
+ +

Set up some simple validations

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb, line 42
+def self.included(klass)
+  return if !klass.column_names.include?("openid_identifier")
+  
+  klass.class_eval do
+    validates_uniqueness_of :openid_identifier, :scope => validations_scope, :if => :using_openid?
+    validate :validate_openid
+    validates_length_of_password_field_options validates_length_of_password_field_options.merge(:if => :validate_password_with_openid?)
+    validates_confirmation_of_password_field_options validates_confirmation_of_password_field_options.merge(:if => :validate_password_with_openid?)
+    validates_length_of_password_confirmation_field_options validates_length_of_password_confirmation_field_options.merge(:if => :validate_password_with_openid?)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ openid_identifier=(value) + + click to toggle source + +
+ + +
+ +

Set the openid_identifier field and also resets the persistence_token if +this value changes.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb, line 55
+def openid_identifier=(value)
+  write_attribute(:openid_identifier, value.blank? ? nil : OpenID.normalize_url(value))
+  reset_persistence_token if openid_identifier_changed?
+rescue OpenID::DiscoveryFailure => e
+  @openid_error = e.message
+end
+
+ +
+ + + + +
+ + +
+ +
+ save(perform_validation = true) { |result| ... } + + click to toggle source + +
+ + +
+ +

This is where all of the magic happens. This is where we hook in and add +all of the OpenID sweetness.

+ +

I had to take this approach because when authenticating with OpenID nonces +and what not are stored in database tables. That being said, the whole save +process for ActiveRecord is wrapped +in a transaction. Trying to authenticate with OpenID in a transaction is +not good because that transaction be get rolled back, thus reversing all of +the OpenID inserts and making OpenID authentication fail every time. So We +need to step outside of the transaction and do our OpenID madness.

+ +

Another advantage of taking this approach is that we can set fields from +their OpenID profile before we save the record, if their OpenID provider +supports it.

+ + +
+ Calls superclass method + +
+ + + +
+
# File lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb, line 72
+def save(perform_validation = true, &block)
+  return false if perform_validation && block_given? && authenticate_with_openid? && !authenticate_with_openid
+  result = super
+  yield(result) if block_given?
+  result
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Private Instance Methods

+
+ + +
+ +
+ attributes_to_save() + + click to toggle source + +
+ + +
+ +

This method works in conjunction with map_saved_attributes.

+ +

Let's say a user fills out a registration form, provides an OpenID and +submits the form. They are then redirected to their OpenID provider. All is +good and they are redirected back. All of those fields they spent time +filling out are forgetten and they have to retype them all. To avoid this, +AuthlogicOpenid saves all of these +attributes in the session and then attempts to restore them. See the source +for what attributes it saves. If you need to block more attributes, or save +more just override this method and do whatever you want.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb, line 133
+def attributes_to_save # :doc:
+  attrs_to_save = attributes.clone.delete_if do |k, v|
+    [:id, :password, crypted_password_field, password_salt_field, :persistence_token, :perishable_token, :single_access_token, :login_count, 
+      :failed_login_count, :last_request_at, :current_login_at, :last_login_at, :current_login_ip, :last_login_ip, :created_at,
+      :updated_at, :lock_version].include?(k.to_sym)
+  end
+  attrs_to_save.merge!(:password => password, :password_confirmation => password_confirmation)
+end
+
+ +
+ + + + +
+ + +
+ +
+ map_openid_registration(registration) + + click to toggle source + +
+ + +
+ +

Override this method to map the OpenID registration fields with fields in +your model. See the required_fields and optional_fields configuration +options to enable this feature.

+ +

Basically you will get a hash of values passed as a single argument. Then +just map them as you see fit. Check out the source of this method for an +example.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb, line 120
+def map_openid_registration(registration) # :doc:
+  self.name ||= registration[:fullname] if respond_to?(:name) && !registration[:fullname].blank?
+  self.first_name ||= registration[:fullname].split(" ").first if respond_to?(:first_name) && !registration[:fullname].blank?
+  self.last_name ||= registration[:fullname].split(" ").last if respond_to?(:last_name) && !registration[:last_name].blank?
+end
+
+ +
+ + + + +
+ + +
+ +
+ map_saved_attributes(attrs) + + click to toggle source + +
+ + +
+ +

This method works in conjunction with attributes_to_save. See that method +for a description of the why these methods exist.

+ +

If the default behavior of this method is not sufficient for you because +you have attr_protected or attr_accessible then override this method and +set them individually. Maybe something like this would be good:

+ +
attrs.each do |key, value|
+  send("#{key}=", value)
+end
+
+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb, line 150
+def map_saved_attributes(attrs) # :doc:
+  self.attributes = attrs
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AuthlogicOpenid/Session.html b/doc/app/AuthlogicOpenid/Session.html new file mode 100644 index 0000000000..600fa8fbbc --- /dev/null +++ b/doc/app/AuthlogicOpenid/Session.html @@ -0,0 +1,175 @@ + + + + + + +module AuthlogicOpenid::Session - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module AuthlogicOpenid::Session +

+ +
+ +

This module is responsible for adding all of the OpenID goodness to the +Authlogic::Session::Base class.

+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ included(klass) + + click to toggle source + +
+ + +
+ +

Add a simple openid_identifier attribute and some validations for the +field.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/session.rb, line 5
+def self.included(klass)
+  klass.class_eval do
+    extend Config
+    include Methods
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AuthlogicOpenid/Session/Config.html b/doc/app/AuthlogicOpenid/Session/Config.html new file mode 100644 index 0000000000..bd18fb1c35 --- /dev/null +++ b/doc/app/AuthlogicOpenid/Session/Config.html @@ -0,0 +1,302 @@ + + + + + + +module AuthlogicOpenid::Session::Config - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module AuthlogicOpenid::Session::Config +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ auto_register(value=true) + + click to toggle source + +
+ + +
+ +

Add this in your Session object to Auto +Register a new user using openid via sreg

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/session.rb, line 33
+def auto_register(value=true)
+  auto_register_value(value)
+end
+
+ +
+ + +
+ Also aliased as: auto_register= +
+ + + +
+ + +
+ +
+ auto_register=(value=true) + +
+ + +
+ + + + + + +
+ + + + +
+ Alias for: auto_register +
+ +
+ + +
+ +
+ auto_register_value(value=nil) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/authlogic_openid/authlogic_openid/session.rb, line 37
+def auto_register_value(value=nil)
+  rw_config(:auto_register,value,false)
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_by_openid_identifier_method(value = nil) + + click to toggle source + +
+ + +
+ +

What method should we call to find a record by the openid_identifier? This +is useful if you want to store multiple openid_identifiers for a single +record. You could do something like:

+ +
class User < ActiveRecord::Base
+  def self.find_by_openid_identifier(identifier)
+    user.first(:conditions => {:openid_identifiers => {:identifier => identifier}})
+  end
+end
+
+ +

Obviously the above depends on what you are calling your assocition, etc. +But you get the point.

+
  • +

    Default: :find_by_openid_identifier

    +
  • +

    Accepts: Symbol

    +
+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/session.rb, line 27
+def find_by_openid_identifier_method(value = nil)
+  rw_config(:find_by_openid_identifier_method, value, :find_by_openid_identifier)
+end
+
+ +
+ + +
+ Also aliased as: find_by_openid_identifier_method= +
+ + + +
+ + +
+ +
+ find_by_openid_identifier_method=(value = nil) + +
+ + +
+ + + + + + +
+ + + + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AuthlogicOpenid/Session/Methods.html b/doc/app/AuthlogicOpenid/Session/Methods.html new file mode 100644 index 0000000000..eb527fee8a --- /dev/null +++ b/doc/app/AuthlogicOpenid/Session/Methods.html @@ -0,0 +1,282 @@ + + + + + + +module AuthlogicOpenid::Session::Methods - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module AuthlogicOpenid::Session::Methods +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ included(klass) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/authlogic_openid/authlogic_openid/session.rb, line 45
+def self.included(klass)
+  klass.class_eval do
+    attr_reader :openid_identifier
+    validate :validate_openid_error
+    validate :validate_by_openid, :if => :authenticating_with_openid?
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ credentials=(value) + + click to toggle source + +
+ + +
+ +

Hooks into credentials so that you can pass an :openid_identifier key.

+ + +
+ Calls superclass method + +
+ + + +
+
# File lib/authlogic_openid/authlogic_openid/session.rb, line 54
+def credentials=(value)
+  super
+  values = value.is_a?(Array) ? value : [value]
+  hash = values.first.is_a?(Hash) ? values.first.with_indifferent_access : nil
+  self.openid_identifier = hash[:openid_identifier] if !hash.nil? && hash.key?(:openid_identifier)
+end
+
+ +
+ + + + +
+ + +
+ +
+ openid_identifier=(value) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/authlogic_openid/authlogic_openid/session.rb, line 61
+def openid_identifier=(value)
+  @openid_identifier = value.blank? ? nil : OpenID.normalize_url(value)
+  @openid_error = nil
+rescue OpenID::DiscoveryFailure => e
+  @openid_identifier = nil
+  @openid_error = e.message
+end
+
+ +
+ + + + +
+ + +
+ +
+ save(&block) + + click to toggle source + +
+ + +
+ +

Cleaers out the block if we are authenticating with OpenID, so that we can +redirect without a DoubleRender error.

+ + +
+ Calls superclass method + +
+ + + +
+
# File lib/authlogic_openid/authlogic_openid/session.rb, line 71
+def save(&block)
+  block = nil if !openid_identifier.blank? && controller.request.env[Rack::OpenID::RESPONSE].blank?
+  super(&block)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/AuthlogicOpenid/Version.html b/doc/app/AuthlogicOpenid/Version.html new file mode 100644 index 0000000000..fdd3ea5945 --- /dev/null +++ b/doc/app/AuthlogicOpenid/Version.html @@ -0,0 +1,438 @@ + + + + + + +class AuthlogicOpenid::Version - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class AuthlogicOpenid::Version +

+ +
+ +

A class for describing the current version of a library. The version +consists of three parts: the major number, the +minor number, and the tiny (or +patch) number.

+ +
+ + + + +
+ + + + + +
+
+

Constants

+
+
+ +
CURRENT + +

The current version as a Version instance

+ + +
MAJOR + +
+ + +
MINOR + +
+ + +
STRING + +

The current version as a String

+ + +
TINY + +
+ + +
+
+ + + +
+
+

Attributes

+
+ + +
+
+ major[R] +
+ +
+ + + +
+
+ +
+
+ minor[R] +
+ +
+ + + +
+
+ +
+
+ tiny[R] +
+ +
+ + + +
+
+ +
+ + + +
+
+

Public Class Methods

+
+ + +
+ +
+ [](major, minor, tiny) + + click to toggle source + +
+ + +
+ +

A convenience method for instantiating a new Version instance with the given major, +minor, and tiny components.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/version.rb, line 10
+def self.[](major, minor, tiny)
+  new(major, minor, tiny)
+end
+
+ +
+ + + + +
+ + +
+ +
+ new(major, minor, tiny) + + click to toggle source + +
+ + +
+ +

Create a new Version object with the given +components.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/version.rb, line 17
+def initialize(major, minor, tiny)
+  @major, @minor, @tiny = major, minor, tiny
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ <=>(version) + + click to toggle source + +
+ + +
+ +

Compare this version to the given version object.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/version.rb, line 22
+def <=>(version)
+  to_i <=> version.to_i
+end
+
+ +
+ + + + +
+ + +
+ +
+ to_a() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/authlogic_openid/authlogic_openid/version.rb, line 38
+def to_a
+  [@major, @minor, @tiny]
+end
+
+ +
+ + + + +
+ + +
+ +
+ to_i() + + click to toggle source + +
+ + +
+ +

Converts this version to a canonical integer that may be compared against +other version objects.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/version.rb, line 34
+def to_i
+  @to_i ||= @major * 1_000_000 + @minor * 1_000 + @tiny
+end
+
+ +
+ + + + +
+ + +
+ +
+ to_s() + + click to toggle source + +
+ + +
+ +

Converts this version object to a string, where each of the three version +components are joined by the '.' character. E.g., 2.0.0.

+ + + + +
+
# File lib/authlogic_openid/authlogic_openid/version.rb, line 28
+def to_s
+  @to_s ||= [@major, @minor, @tiny].join(".")
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/Comment.html b/doc/app/Comment.html new file mode 100644 index 0000000000..e945569546 --- /dev/null +++ b/doc/app/Comment.html @@ -0,0 +1,851 @@ + + + + + + +class Comment - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Comment +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ comment_weekly_tallies(span = 52, time = Time.now) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 26
+def self.comment_weekly_tallies(span = 52, time = Time.now)
+  weeks = {}
+  (0..span).each do |week|
+    weeks[span - week] = Comment.select(:timestamp)
+                                .where(timestamp: time.to_i - week.weeks.to_i..time.to_i - (week - 1).weeks.to_i)
+                                .count
+  end
+  weeks
+end
+
+ +
+ + + + +
+ + +
+ +
+ inheritance_column() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 18
+def self.inheritance_column
+  'rails_type'
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ answer_comment_notify(current_user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 126
+def answer_comment_notify(current_user)
+  # notify answer author
+  if answer.uid != current_user.uid
+    CommentMailer.notify_answer_author(answer.author, self).deliver
+  end
+
+  notify_callout_users
+
+  already = mentioned_users.collect(&:uid) + [answer.uid]
+  uids = []
+  # notify other answer commenter and users who liked the answer
+  # except mentioned users and answer author
+  (answer.comments.collect(&:uid) + answer.likers.collect(&:uid)).uniq.each do |u|
+    uids << u unless already.include?(u)
+  end
+
+  notify_users(uids, current_user)
+  notify_tag_followers(already + uids)
+end
+
+ +
+ + + + +
+ + +
+ +
+ body() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 44
+def body
+  finder = comment.gsub(Callouts.const_get(:FINDER), Callouts.const_get(:PRETTYLINKMD))
+  finder = finder.gsub(Callouts.const_get(:HASHTAGNUMBER), Callouts.const_get(:NODELINKMD)) 
+  finder = finder.gsub(Callouts.const_get(:HASHTAG), Callouts.const_get(:HASHLINKMD))  
+end
+
+ +
+ + + + +
+ + +
+ +
+ created_at() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 40
+def created_at
+  Time.at(timestamp)
+end
+
+ +
+ + + + +
+ + +
+ +
+ followers_of_mentioned_tags() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 82
+def followers_of_mentioned_tags
+  tagnames = comment.scan(Callouts.const_get(:HASHTAG))
+  tagnames.map { |tagname| Tag.followers(tagname[1]) }.flatten.uniq
+end
+
+ +
+ + + + +
+ + +
+ +
+ icon() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 50
+def icon
+  "<i class='icon-comment'></i>"
+end
+
+ +
+ + + + +
+ + +
+ +
+ id() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 36
+def id
+  cid
+end
+
+ +
+ + + + +
+ + +
+ +
+ mentioned_users() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 77
+def mentioned_users
+  usernames = comment.scan(Callouts.const_get(:FINDER))
+  User.where(username: usernames.map { |m| m[1] }).uniq
+end
+
+ +
+ + + + +
+ + +
+ +
+ next_thread() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 62
+def next_thread
+  (thread.split('/').first.to_i(16) + 1).to_s(16).rjust(2, '0') + '/'
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify(current_user) + + click to toggle source + +
+ + +
+ +

email all users in this thread plus all who've starred it

+ + + + +
+
# File app/models/comment.rb, line 111
+def notify(current_user)
+  if parent.uid != current_user.uid
+    CommentMailer.notify_note_author(parent.author, self).deliver
+  end
+
+  notify_callout_users
+
+  # notify other commenters, revisers, and likers, but not those already @called out
+  already = mentioned_users.collect(&:uid) + [parent.uid]
+  uids = uids_to_notify - already
+
+  notify_users(uids, current_user)
+  notify_tag_followers(already + uids)
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_callout_users() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 87
+def notify_callout_users
+  # notify mentioned users
+  mentioned_users.each do |user|
+    CommentMailer.notify_callout(self, user) if user.username != author.username
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_tag_followers(already_mailed_uids = []) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 94
+def notify_tag_followers(already_mailed_uids = [])
+  # notify users who follow the tags mentioned in the comment
+  followers_of_mentioned_tags.each do |user|
+    CommentMailer.notify_tag_followers(self, user) unless already_mailed_uids.include?(user.uid)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_users(uids, current_user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 101
+def notify_users(uids, current_user)
+  DrupalUser.where('uid IN (?)', uids).each do |user|
+    if user.uid != current_user.uid
+      CommentMailer.notify(user.user, self).deliver
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ parent() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 66
+def parent
+  if aid == 0
+    node
+  else
+    answer.node
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ tags() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 58
+def tags
+  []
+end
+
+ +
+ + + + +
+ + +
+ +
+ thread_participants() + + click to toggle source + +
+ + +
+ +

users who are involved in this comment thread

+ + + + +
+
# File app/models/comment.rb, line 75
+def thread_participants; end
+
+ +
+ + + + +
+ + +
+ +
+ type() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/comment.rb, line 54
+def type
+  'comment'
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/CommentController.html b/doc/app/CommentController.html new file mode 100644 index 0000000000..cc6de42ff1 --- /dev/null +++ b/doc/app/CommentController.html @@ -0,0 +1,508 @@ + + + + + + +class CommentController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class CommentController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ answer_create() + + click to toggle source + +
+ + +
+ +

create answer comments

+ + + + +
+
# File app/controllers/comment_controller.rb, line 71
+def answer_create
+  @answer_id = params[:aid]
+  @comment = Comment.new(
+    uid: current_user.uid,
+    aid: params[:aid],
+    comment: params[:body],
+    timestamp: Time.now.to_i
+  )
+  if @comment.save
+    @comment.answer_comment_notify(current_user)
+    respond_to do |format|
+      format.js { render template: 'comment/create' }
+    end
+  else
+    flash[:error] = 'The comment could not be saved.'
+    render text: 'failure'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ +

handle some errors!!!!!! create node comments

+ + + + +
+
# File app/controllers/comment_controller.rb, line 15
+def create
+  @node = Node.find params[:id]
+  @body = params[:body]
+  @user = current_user
+
+  begin
+    @comment = create_comment(@node, @user, @body)
+    respond_with do |format|
+      if params[:type] && params[:type] == 'question'
+        @answer_id = 0
+        format.js
+      else
+        format.html do
+          if request.xhr?
+            render partial: 'notes/comment', locals: { comment: @comment }
+          else
+            flash[:notice] = 'Comment posted.'
+            redirect_to @node.path + '#last' # to last comment
+          end
+        end
+      end
+    end
+  rescue CommentError
+    flash[:error] = 'The comment could not be saved.'
+    render text: 'failure'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ create_by_token() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/comment_controller.rb, line 43
+def create_by_token
+  @node = Node.find params[:id]
+  @user = User.find_by(username: params[:username])
+  @body = params[:body]
+  @token = request.headers["HTTP_TOKEN"]
+
+  if @user && @user.token == @token
+    begin
+      # The create_comment is a function that has been defined inside the
+      # CommentHelper module inside app/helpers/comment_helper.rb and can be
+      # used in here because the module was `include`d right at the beginning
+      @comment = create_comment(@node, @user, @body)
+      respond_to do |format|
+        format.all { render :nothing => true, :status => :created }
+      end
+    rescue CommentError
+      respond_to do |format|
+        format.all { render :nothing => true, :status => :bad_request }
+      end
+    end
+  else
+    respond_to do |format|
+      format.all { render :nothing => true, :status => :unauthorized }
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/comment_controller.rb, line 111
+def delete
+  @comment = Comment.find params[:id]
+
+  comments_node_and_path
+
+  if current_user.uid == @node.uid ||
+     @comment.uid == current_user.uid ||
+     current_user.role == 'admin' ||
+     current_user.role == 'moderator'
+
+    if @comment.delete
+      respond_with do |format|
+        if params[:type] && params[:type] == 'question'
+          @answer_id = @comment.aid
+          format.js
+        else
+          format.html do
+            if request.xhr?
+              render text: 'success'
+            else
+              flash[:notice] = 'Comment deleted.'
+              redirect_to '/' + @node.path
+            end
+          end
+        end
+      end
+    else
+      flash[:error] = 'The comment could not be deleted.'
+      render text: 'failure'
+    end
+  else
+    prompt_login 'Only the comment or post author can delete this comment'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/comment_controller.rb, line 7
+def index
+  @comments = Comment.paginate(page: params[:page], per_page: 30)
+                     .order('timestamp DESC')
+  render template: 'comments/index'
+end
+
+ +
+ + + + +
+ + +
+ +
+ make_answer() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/comment_controller.rb, line 146
+def make_answer
+  @comment = Comment.find params[:id]
+  comments_node_and_path
+
+  if @comment.uid == current_user.uid
+    @answer = Answer.new(
+        nid: @comment.nid,
+        uid: @comment.uid,
+        content: @comment.comment
+    )
+
+    if @answer.save && @comment.delete
+      @answer.answer_notify(current_user)
+      @answer_id = @comment.aid
+      respond_with do |format|
+        format.js { render template: 'comment/make_answer' }
+      end
+    else
+      flash[:error] = 'The comment could not be promoted to answer.'
+      render text: 'failure'
+    end
+  else
+    prompt_login 'Only the comment author can promote this comment to answer'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ update() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/comment_controller.rb, line 90
+def update
+  @comment = Comment.find params[:id]
+
+  comments_node_and_path
+
+  if @comment.uid == current_user.uid
+    # should abstract ".comment" to ".body" for future migration to native db
+    @comment.comment = params[:body]
+    if @comment.save
+      flash[:notice] = 'Comment updated.'
+      redirect_to @path + '?_=' + Time.now.to_i.to_s
+    else
+      flash[:error] = 'The comment could not be updated.'
+      redirect_to @path
+    end
+  else
+    flash[:error] = 'Only the author of the comment can edit it.'
+    redirect_to @path
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/CommentHelper.html b/doc/app/CommentHelper.html new file mode 100644 index 0000000000..aa9b5400ab --- /dev/null +++ b/doc/app/CommentHelper.html @@ -0,0 +1,152 @@ + + + + + + +module CommentHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module CommentHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ create_comment(node, user, body) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/helpers/comment_helper.rb, line 5
+def create_comment(node, user, body)
+  @comment = node.add_comment(uid: user.uid, body: body)
+  if user && @comment.save
+    @comment.notify user
+    return @comment
+  else
+    raise CommentError.new()
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/CommentHelper/CommentError.html b/doc/app/CommentHelper/CommentError.html new file mode 100644 index 0000000000..570f6b9c81 --- /dev/null +++ b/doc/app/CommentHelper/CommentError.html @@ -0,0 +1,102 @@ + + + + + + +class CommentHelper::CommentError - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class CommentHelper::CommentError +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/CommentMailer.html b/doc/app/CommentMailer.html new file mode 100644 index 0000000000..56c3d7987e --- /dev/null +++ b/doc/app/CommentMailer.html @@ -0,0 +1,357 @@ + + + + + + +class CommentMailer - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class CommentMailer +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ notify(user, comment) + + click to toggle source + +
+ + +
+ +

CommentMailer.notify_of_comment(user,self).deliver

+ + + + +
+
# File app/mailers/comment_mailer.rb, line 7
+def notify(user, comment)
+  @user = user
+  @comment = comment
+  @footer = feature('email-footer')
+  mail(to: user.email, subject: "New comment on '" + comment.parent.title + "'")
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_answer_author(user, comment) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/comment_mailer.rb, line 43
+def notify_answer_author(user, comment)
+  @user = user
+  @comment = comment
+  @footer = feature('email-footer')
+  mail(to: user.email, subject: "New comment on your answer on '" + comment.parent.title + "'")
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_barnstar(user, note) + + click to toggle source + +
+ + +
+ +

user is awarder, not awardee

+ + + + +
+
# File app/mailers/comment_mailer.rb, line 22
+def notify_barnstar(user, note)
+  @giver = user.drupal_user
+  @note = note
+  @footer = feature('email-footer')
+  mail(to: note.author.email, subject: 'You were awarded a Barnstar!').deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_callout(comment, user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/comment_mailer.rb, line 29
+def notify_callout(comment, user)
+  @user = user
+  @comment = comment
+  @footer = feature('email-footer')
+  mail(to: user.email, subject: 'You were mentioned in a comment.').deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_note_author(user, comment) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/comment_mailer.rb, line 14
+def notify_note_author(user, comment)
+  @user = user
+  @comment = comment
+  @footer = feature('email-footer')
+  mail(to: user.email, subject: "New comment on '" + comment.node.title + "'")
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_tag_followers(comment, user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/comment_mailer.rb, line 36
+def notify_tag_followers(comment, user)
+  @user = user
+  @comment = comment
+  @footer = feature('email-footer')
+  mail(to: user.email, subject: 'A tag you follow was mentioned in a comment.').deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/CommentsShared.html b/doc/app/CommentsShared.html new file mode 100644 index 0000000000..edbc85af85 --- /dev/null +++ b/doc/app/CommentsShared.html @@ -0,0 +1,338 @@ + + + + + + +module CommentsShared - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module CommentsShared +

+ +
+ +

Active Support concerns are a good way to use modules that can used across +different models Refer to this link: stackoverflow.com/questions/14541823/how-to-use-concerns-in-rails-4

+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ author() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/comments_shared.rb, line 12
+def author
+  DrupalUser.find_by(uid: uid)
+end
+
+ +
+ + + + +
+ + +
+ +
+ body_email(host = 'publiclab.org') + + click to toggle source + +
+ + +
+ +

filtered version additionally appending http/https

+ +
protocol to protocol-relative URLslike "/foo"
+ + + + +
+
# File app/models/concerns/comments_shared.rb, line 8
+def body_email(host = 'publiclab.org')
+  body.gsub(/([\s|"|'|\[|\(])(\/\/)([\w]?\.?#{host})/, '\1https://\3')
+end
+
+ +
+ + + + +
+ + +
+ +
+ parent_commenter_uids() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/comments_shared.rb, line 16
+def parent_commenter_uids
+  parent.comments.collect(&:uid)
+end
+
+ +
+ + + + +
+ + +
+ +
+ parent_liker_uids() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/comments_shared.rb, line 20
+def parent_liker_uids
+  parent.likers.collect(&:uid)
+end
+
+ +
+ + + + +
+ + +
+ +
+ parent_reviser_uids() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/comments_shared.rb, line 24
+def parent_reviser_uids
+  (parent.revision.collect(&:uid).uniq - [parent.author.uid])
+end
+
+ +
+ + + + +
+ + +
+ +
+ uids_to_notify() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/comments_shared.rb, line 28
+def uids_to_notify
+  (parent_commenter_uids + parent_liker_uids + parent_reviser_uids).uniq
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/DocList.html b/doc/app/DocList.html new file mode 100644 index 0000000000..4d7af575dd --- /dev/null +++ b/doc/app/DocList.html @@ -0,0 +1,328 @@ + + + + + + +class DocList - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DocList +

+ +
+ +

List of documents returned from a search

+ +
+ + + + +
+ + + + + + + +
+
+

Attributes

+
+ + +
+
+ items[RW] +
+ +
+ + + +
+
+ +
+
+ pageCount[RW] +
+ +
+ + + +
+
+ +
+
+ pageNum[RW] +
+ +
+ + + +
+
+ +
+
+ srchParams[RW] +
+ +
+ + + +
+
+ +
+ + + +
+
+

Public Class Methods

+
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/doc_list.rb, line 5
+def initialize; end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ addAll(dlist) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/doc_list.rb, line 12
+def addAll(dlist)
+  @items ||= []
+  dlist.each { |docItem| @items << docItem } unless dlist.nil?
+end
+
+ +
+ + + + +
+ + +
+ +
+ addDoc(ndoc) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/doc_list.rb, line 7
+def addDoc(ndoc)
+  @items ||= []
+  @items << ndoc
+end
+
+ +
+ + + + +
+ + +
+ +
+ getDocs() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/doc_list.rb, line 17
+def getDocs
+  @items
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/DocList/Entity.html b/doc/app/DocList/Entity.html new file mode 100644 index 0000000000..188edfca46 --- /dev/null +++ b/doc/app/DocList/Entity.html @@ -0,0 +1,107 @@ + + + + + + +class DocList::Entity - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DocList::Entity +

+ +
+ +

This subclass is used to auto-generate the RESTful data structure. It is +generally not useful for internal Ruby usage

+ +
but must be included for full RESTful functionality.
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/DocList/Entity/DocResult.html b/doc/app/DocList/Entity/DocResult.html new file mode 100644 index 0000000000..c125890643 --- /dev/null +++ b/doc/app/DocList/Entity/DocResult.html @@ -0,0 +1,95 @@ + + + + + + +module DocList::Entity::DocResult - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module DocList::Entity::DocResult +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/DocList/Entity/SearchRequest.html b/doc/app/DocList/Entity/SearchRequest.html new file mode 100644 index 0000000000..fe16dc5c85 --- /dev/null +++ b/doc/app/DocList/Entity/SearchRequest.html @@ -0,0 +1,95 @@ + + + + + + +module DocList::Entity::SearchRequest - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module DocList::Entity::SearchRequest +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/DocResult.html b/doc/app/DocResult.html new file mode 100644 index 0000000000..c0e2a0027b --- /dev/null +++ b/doc/app/DocResult.html @@ -0,0 +1,282 @@ + + + + + + +class DocResult - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DocResult +

+ +
+ +

A DocResult is an individual return item for a +document (web page) search

+ +
+ + + + +
+ + + + + + + +
+
+

Attributes

+
+ + +
+
+ docId[RW] +
+ +
+ + + +
+
+ +
+
+ docScore[RW] +
+ +
+ + + +
+
+ +
+
+ docSummary[RW] +
+ +
+ + + +
+
+ +
+
+ docTitle[RW] +
+ +
+ + + +
+
+ +
+
+ docType[RW] +
+ +
+ + + +
+
+ +
+
+ docUrl[RW] +
+ +
+ + + +
+
+ +
+ + + +
+
+

Public Class Methods

+
+ + +
+ +
+ fromSearch(idval, typeval, urlval, titleval, sumval, scoreval) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/doc_result.rb, line 7
+def self.fromSearch(idval, typeval, urlval, titleval, sumval, scoreval)
+  obj = new
+  obj.docId = idval
+  obj.docType = typeval
+  obj.docUrl = urlval
+  obj.docTitle = titleval
+  obj.docSummary = sumval
+  obj.docScore = scoreval
+  obj
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/doc_result.rb, line 5
+def initialize; end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/DocResult/Entity.html b/doc/app/DocResult/Entity.html new file mode 100644 index 0000000000..b86a978ef4 --- /dev/null +++ b/doc/app/DocResult/Entity.html @@ -0,0 +1,107 @@ + + + + + + +class DocResult::Entity - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DocResult::Entity +

+ +
+ +

This subclass is used to auto-generate the RESTful data structure. It is +generally not useful for internal Ruby usage

+ +
but must be included for full RESTful functionality.
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/DrupalContentFieldImageGallery.html b/doc/app/DrupalContentFieldImageGallery.html new file mode 100644 index 0000000000..ffb95944af --- /dev/null +++ b/doc/app/DrupalContentFieldImageGallery.html @@ -0,0 +1,260 @@ + + + + + + +class DrupalContentFieldImageGallery - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalContentFieldImageGallery +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ description() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_field_image_gallery.rb, line 22
+def description
+  PHP.unserialize(field_image_gallery_data)['description']
+rescue
+  ''
+end
+
+ +
+ + + + +
+ + +
+ +
+ fid() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_field_image_gallery.rb, line 14
+def fid
+  field_image_gallery_fid
+end
+
+ +
+ + + + +
+ + +
+ +
+ file() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_field_image_gallery.rb, line 10
+def file
+  drupal_file
+end
+
+ +
+ + + + +
+ + +
+ +
+ image() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_field_image_gallery.rb, line 18
+def image
+  DrupalFile.find field_image_gallery_fid
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/DrupalContentFieldMapEditor.html b/doc/app/DrupalContentFieldMapEditor.html new file mode 100644 index 0000000000..8bdaa60063 --- /dev/null +++ b/doc/app/DrupalContentFieldMapEditor.html @@ -0,0 +1,102 @@ + + + + + + +class DrupalContentFieldMapEditor - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalContentFieldMapEditor +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/DrupalContentFieldMapper.html b/doc/app/DrupalContentFieldMapper.html new file mode 100644 index 0000000000..4072354745 --- /dev/null +++ b/doc/app/DrupalContentFieldMapper.html @@ -0,0 +1,102 @@ + + + + + + +class DrupalContentFieldMapper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalContentFieldMapper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/DrupalContentTypeMap.html b/doc/app/DrupalContentTypeMap.html new file mode 100644 index 0000000000..ff15135653 --- /dev/null +++ b/doc/app/DrupalContentTypeMap.html @@ -0,0 +1,401 @@ + + + + + + +class DrupalContentTypeMap - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalContentTypeMap +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ captured_on() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_type_map.rb, line 46
+def captured_on
+  field_capture_date_value
+end
+
+ +
+ + + + +
+ + +
+ +
+ cartographer_notes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_type_map.rb, line 27
+def cartographer_notes
+  field_cartographer_notes_value
+end
+
+ +
+ + + + +
+ + +
+ +
+ license() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_type_map.rb, line 31
+def license
+  l = "<a href='http://creativecommons.org/publicdomain/zero/1.0/'>Public Domain</a>" if field_license_value == 'publicdomain'
+  l = "<a href='http://creativecommons.org/licenses/by/3.0/'>CC-BY</a>" if field_license_value == 'cc-by'
+  l = "<a href='http://creativecommons.org/licenses/by-sa/3.0/'>CC-BY-SA</a>" if field_license_value == 'cc-by-sa'
+  l
+end
+
+ +
+ + + + +
+ + +
+ +
+ max_zoom() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_type_map.rb, line 23
+def max_zoom
+  field_zoom_max_value
+end
+
+ +
+ + + + +
+ + +
+ +
+ min_zoom() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_type_map.rb, line 19
+def min_zoom
+  field_zoom_min_value
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_type_map.rb, line 38
+def notes
+  field_notes_value
+end
+
+ +
+ + + + +
+ + +
+ +
+ published_on() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_type_map.rb, line 42
+def published_on
+  field_publication_date_value
+end
+
+ +
+ + + + +
+ + +
+ +
+ tms() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_content_type_map.rb, line 15
+def tms
+  field_tms_url_value
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/DrupalFile.html b/doc/app/DrupalFile.html new file mode 100644 index 0000000000..de71bc8673 --- /dev/null +++ b/doc/app/DrupalFile.html @@ -0,0 +1,235 @@ + + + + + + +class DrupalFile - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalFile +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ filetype() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_file.rb, line 7
+def filetype
+  filename[-3..filename.length].downcase
+end
+
+ +
+ + + + +
+ + +
+ +
+ is_image?() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_file.rb, line 11
+def is_image?
+  (filetype == 'jpg' || filetype == 'jpeg' || filetype == 'gif' || filetype == 'png')
+end
+
+ +
+ + + + +
+ + +
+ +
+ path(size = :default) + + click to toggle source + +
+ + +
+ +

swap legacy Drupal static routes

+ + + + +
+
# File app/models/drupal_file.rb, line 16
+def path(size = :default)
+  if is_image?
+    if size == :thumb
+      "/#{filepath.gsub('sites/default/files/', 'sites/default/files/imagecache/thumb/')}"
+    elsif size == :default
+      "/#{filepath.gsub('sites/default/files/', 'sites/default/files/imagecache/default/')}"
+    elsif size == :large
+      "/#{filepath.gsub('sites/default/files/', 'sites/default/files/imagecache/default/')}"
+    elsif size == :original
+      "/#{filepath}"
+    end
+  else
+    "/#{filepath}"
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/DrupalMainImage.html b/doc/app/DrupalMainImage.html new file mode 100644 index 0000000000..ebe8e65806 --- /dev/null +++ b/doc/app/DrupalMainImage.html @@ -0,0 +1,102 @@ + + + + + + +class DrupalMainImage - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalMainImage +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/DrupalProfileField.html b/doc/app/DrupalProfileField.html new file mode 100644 index 0000000000..2d42dca15b --- /dev/null +++ b/doc/app/DrupalProfileField.html @@ -0,0 +1,153 @@ + + + + + + +class DrupalProfileField - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalProfileField +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ inheritance_column() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_profile_field.rb, line 6
+def self.inheritance_column
+  'rails_type'
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/DrupalProfileValue.html b/doc/app/DrupalProfileValue.html new file mode 100644 index 0000000000..aa800de985 --- /dev/null +++ b/doc/app/DrupalProfileValue.html @@ -0,0 +1,102 @@ + + + + + + +class DrupalProfileValue - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalProfileValue +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/DrupalUpload.html b/doc/app/DrupalUpload.html new file mode 100644 index 0000000000..9cc8a24944 --- /dev/null +++ b/doc/app/DrupalUpload.html @@ -0,0 +1,188 @@ + + + + + + +class DrupalUpload - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalUpload +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ file() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_upload.rb, line 11
+def file
+  drupal_file
+end
+
+ +
+ + + + +
+ + +
+ +
+ node() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_upload.rb, line 7
+def node
+  node
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/DrupalUser.html b/doc/app/DrupalUser.html new file mode 100644 index 0000000000..92d28ec3a0 --- /dev/null +++ b/doc/app/DrupalUser.html @@ -0,0 +1,1115 @@ + + + + + + +class DrupalUser - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class DrupalUser +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ ban() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 60
+def ban
+  self.status = 0
+  decrease_likes_banned
+  save
+  # user is logged out next time they access current_user in a controller; see application controller
+  self
+end
+
+ +
+ + + + +
+ + +
+ +
+ bio() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 23
+def bio
+  user.bio
+end
+
+ +
+ + + + +
+ + +
+ +
+ created_at() + + click to toggle source + +
+ + +
+ +

Rails-style adaptors:

+ + + + +
+
# File app/models/drupal_user.rb, line 37
+def created_at
+  Time.at(created)
+end
+
+ +
+ + + + +
+ + +
+ +
+ email() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 75
+def email
+  mail
+end
+
+ +
+ + + + +
+ + +
+ +
+ first_time_poster() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 79
+def first_time_poster
+  user.first_time_poster
+end
+
+ +
+ + + + +
+ + +
+ +
+ last() + + click to toggle source + +
+ + +
+ +

last node

+ + + + +
+
# File app/models/drupal_user.rb, line 107
+def last
+  Node.limit(1)
+      .where(uid: uid)
+      .order('changed DESC')
+      .first
+end
+
+ +
+ + + + +
+ + +
+ +
+ like_count() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 87
+def like_count
+  NodeSelection.where(user_id: uid, liking: true).count
+end
+
+ +
+ + + + +
+ + +
+ +
+ liked_notes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 91
+def liked_notes
+  Node.includes(:node_selections)
+      .references(:node_selections)
+      .where("type = 'note' AND node_selections.liking = ? AND node_selections.user_id = ? AND node.status = 1", true, uid)
+      .order('node_selections.nid DESC')
+end
+
+ +
+ + + + +
+ + +
+ +
+ liked_pages() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 98
+def liked_pages
+  NodeSelection.where("status = 1 AND user_id = ? AND liking = ? AND (node.type = 'page' OR node.type = 'tool' OR node.type = 'place')", uid, true)
+               .includes(:node)
+               .references(:node)
+               .collect(&:node)
+               .reverse
+end
+
+ +
+ + + + +
+ + +
+ +
+ likes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 83
+def likes
+  NodeSelection.where(user_id: uid, liking: true)
+end
+
+ +
+ + + + +
+ + +
+ +
+ migrate() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 170
+def migrate
+  u = User.new(username: name,
+               id: uid,
+               email: mail,
+               openid_identifier: '//old.publiclab.org/user/' + uid.to_s + '/identity')
+  u.persistence_token = rand(100_000_000)
+  if u.save(validate: false) # <= because validations checks for conflict with existing drupal_user.name
+    key = u.generate_reset_key
+    PasswordResetMailer.reset_notify(u, key)
+    return true
+  else
+    return false
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ moderate() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 47
+def moderate
+  self.status = 5
+  save
+  # user is logged out next time they access current_user in a controller; see application controller
+  self
+end
+
+ +
+ + + + +
+ + +
+ +
+ node_count() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 126
+def node_count
+  Node.where(status: 1, uid: uid).count + Revision.where(uid: uid).count
+end
+
+ +
+ + + + +
+ + +
+ +
+ note_count() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 122
+def note_count
+  Node.where(status: 1, uid: uid, type: 'note').count
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 118
+def notes
+  user.notes
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes_for_tags(tagnames) + + click to toggle source + +
+ + +
+ +

accepts array of tag names (strings)

+ + + + +
+
# File app/models/drupal_user.rb, line 131
+def notes_for_tags(tagnames)
+  all_nodes = Node.order('nid DESC').where(type: 'note', status: 1, uid: uid)
+  node_ids = []
+  all_nodes.each do |node|
+    node.tags.each do |tag|
+      tagnames.each do |tagname|
+        node_ids << node.nid if tag.name == tagname
+      end
+    end
+  end
+  Node.find(node_ids.uniq, order: 'nid DESC')
+end
+
+ +
+ + + + +
+ + +
+ +
+ profile_values() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 114
+def profile_values
+  drupal_profile_values
+end
+
+ +
+ + + + +
+ + +
+ +
+ role() + + click to toggle source + +
+ + +
+ +

End rails-style adaptors

+ + + + +
+
# File app/models/drupal_user.rb, line 43
+def role
+  user.role if user
+end
+
+ +
+ + + + +
+ + +
+ +
+ tag_counts() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 156
+def tag_counts
+  tags = {}
+  Node.order('nid DESC').where(type: 'note', status: 1, uid: uid).limit(20).each do |node|
+    node.tags.each do |tag|
+      if tags[tag.name]
+        tags[tag.name] += 1
+      else
+        tags[tag.name] = 1
+      end
+    end
+  end
+  tags
+end
+
+ +
+ + + + +
+ + +
+ +
+ tagnames(limit = 20, defaults = true) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 152
+def tagnames(limit = 20, defaults = true)
+  self.user.tagnames(limit, defaults)
+end
+
+ +
+ + + + +
+ + +
+ +
+ tags(limit = 10) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 148
+def tags(limit = 10)
+  self.user.tags(limit)
+end
+
+ +
+ + + + +
+ + +
+ +
+ unban() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 68
+def unban
+  self.status = 1
+  increase_likes_unbanned
+  save
+  self
+end
+
+ +
+ + + + +
+ + +
+ +
+ unmoderate() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 54
+def unmoderate
+  self.status = 1
+  save
+  self
+end
+
+ +
+ + + + +
+ + +
+ +
+ user() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 19
+def user
+  User.where(username: name).first
+end
+
+ +
+ + + + +
+ + +
+ +
+ user_tags() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 144
+def user_tags
+  self.user.user_tags
+end
+
+ +
+ + + + +
+ + +
+ +
+ username() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 27
+def username
+  name
+end
+
+ +
+ + + + +
+ + +
+ +
+ using_new_site?() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/drupal_user.rb, line 31
+def using_new_site?
+  !User.find_by(username: name).nil?
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/EditorController.html b/doc/app/EditorController.html new file mode 100644 index 0000000000..4bfc69d89f --- /dev/null +++ b/doc/app/EditorController.html @@ -0,0 +1,287 @@ + + + + + + +class EditorController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class EditorController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ editor() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/editor_controller.rb, line 24
+def editor
+  redirect_to "/post?#{request.env['QUERY_STRING']}"
+end
+
+ +
+ + + + +
+ + +
+ +
+ legacy() + + click to toggle source + +
+ + +
+ +

main image via URL passed as GET param

+ + + + +
+
# File app/controllers/editor_controller.rb, line 5
+def legacy
+  # /post/?i=http://myurl.com/image.jpg
+  flash.now[:notice] = "This is the legacy editor. For the new rich editor, <a href='/editor'>click here</a>."
+  if params[:i]
+    @image = Image.new(remote_url: params[:i],
+                       uid: current_user.uid)
+    flash[:error] = 'The image could not be saved.' unless @image.save!
+  end
+  if params[:n] && !params[:body] # use another node body as a template
+    node = Node.find(params[:n])
+    params[:body] = node.body if node
+  end
+  if params[:tags] && params[:tags].include?('question:')
+    redirect_to "/questions/new?#{request.env['QUERY_STRING']}"
+  else
+    render template: 'editor/post'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ post() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/editor_controller.rb, line 28
+def post
+  if params[:tags] && params[:tags].include?('question:')
+    redirect_to "/questions/new?#{request.env['QUERY_STRING']}"
+  elsif params[:legacy] || params[:template] == 'event'
+    legacy
+  else
+    rich
+    render '/editor/rich'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ rich() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/editor_controller.rb, line 39
+def rich
+  flash.now[:notice] = "This is the new rich editor. For the legacy editor, <a href='/post?#{request.env['QUERY_STRING']}&legacy=true' class='legacy-button'>click here</a>."
+  if params[:main_image] && Image.find_by(id: params[:main_image])
+    @main_image = Image.find_by(id: params[:main_image]).path
+  end
+  if params[:n] && !params[:body] # use another node body as a template
+    node = Node.find(params[:n])
+    params[:body] = node.body if node
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/FeaturesController.html b/doc/app/FeaturesController.html new file mode 100644 index 0000000000..4e62d1bd18 --- /dev/null +++ b/doc/app/FeaturesController.html @@ -0,0 +1,391 @@ + + + + + + +class FeaturesController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class FeaturesController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/features_controller.rb, line 30
+def create
+  if current_user.role != 'admin'
+    flash[:warning] = 'Only admins may edit features.'
+    redirect_to '/features?_=' + Time.now.to_i.to_s
+  else
+    @node = Node.new(uid:   current_user.id,
+                     title: params[:title],
+                     type:  'feature')
+    if @node.valid?
+      saved = true
+      @revision = false
+      ActiveRecord::Base.transaction do
+        @node.save!
+        @revision = @node.new_revision(uid:   current_user.id,
+                                       title: params[:title],
+                                       body:  params[:body])
+        if @revision.valid?
+          @revision.save!
+          @node.vid = @revision.vid
+          @node.save!
+        else
+          saved = false
+          @node.destroy
+        end
+      end
+    end
+    if saved
+      flash[:notice] = 'Feature saved.'
+      redirect_to '/features?_=' + Time.now.to_i.to_s
+    else
+      render template: 'features/new'
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ edit() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/features_controller.rb, line 21
+def edit
+  if current_user.role != 'admin'
+    flash[:warning] = 'Only admins may edit features.'
+    redirect_to '/features'
+  else
+    @node = Node.find params[:id]
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ embed() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/features_controller.rb, line 9
+def embed
+  @node = Node.find_by(title: params[:id])
+  render layout: false
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/features_controller.rb, line 4
+def index
+  @features = Node.where(type: 'feature')
+                  .paginate(page: params[:page])
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/features_controller.rb, line 14
+def new
+  if current_user.role != 'admin'
+    flash[:warning] = 'Only admins may edit features.'
+    redirect_to '/features'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ update() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/features_controller.rb, line 65
+def update
+  if current_user.role != 'admin'
+    flash[:warning] = 'Only admins may edit features.'
+    redirect_to '/features?_=' + Time.now.to_i.to_s
+  else
+    @node = Node.find(params[:id])
+    @revision = @node.new_revision(uid: current_user.uid)
+    @revision.title = params[:title] || @node.latest.title
+    @revision.body = params[:body] if params[:body]
+    if @revision.valid?
+      ActiveRecord::Base.transaction do
+        @revision.save
+        @node.vid = @revision.vid
+        @node.title = @revision.title
+        @node.save
+      end
+      ActionController::Base.new.expire_fragment("feature_#{params[:title]}")
+      flash[:notice] = 'Edits saved and cache cleared.'
+      redirect_to '/features?_=' + Time.now.to_i.to_s
+    else
+      flash[:error] = 'Your edit could not be saved.'
+      render action: 'edit'
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/FeaturesHelper.html b/doc/app/FeaturesHelper.html new file mode 100644 index 0000000000..b42b1e940b --- /dev/null +++ b/doc/app/FeaturesHelper.html @@ -0,0 +1,95 @@ + + + + + + +module FeaturesHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module FeaturesHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/HomeController.html b/doc/app/HomeController.html new file mode 100644 index 0000000000..714417895f --- /dev/null +++ b/doc/app/HomeController.html @@ -0,0 +1,467 @@ + + + + + + +class HomeController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class HomeController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ activity() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/home_controller.rb, line 76
+def activity
+  blog = Tag.find_nodes_by_type('blog', 'note', 1).first
+  # remove "classroom" postings; also switch to an EXCEPT operator in sql, see https://github.com/publiclab/plots2/issues/375
+  hidden_nids = Node.joins(:node_tag)
+                    .joins('LEFT OUTER JOIN term_data ON term_data.tid = community_tags.tid')
+                    .select('node.*, term_data.*, community_tags.*')
+                    .where(type: 'note', status: 1)
+                    .where('term_data.name = (?)', 'hidden:response')
+                    .collect(&:nid)
+  notes = Node.where(type: 'note')
+              .where('node.nid NOT IN (?)', hidden_nids + [0]) # in case hidden_nids is empty
+              .order('nid DESC')
+              .page(params[:page])
+  notes = notes.where('nid != (?)', blog.nid) if blog
+
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    notes = notes.where('(node.status = 1 OR node.status = 4)')
+  elsif current_user
+    notes = notes.where('(node.status = 1 OR (node.status = 4 AND node.uid = ?))', current_user.uid)
+  else
+    notes = notes.where('node.status = 1')
+  end
+  notes = notes.to_a # ensure it can be serialized for caching
+
+  # include revisions, then mix with new pages:
+  wikis = Node.where(type: 'page', status: 1)
+              .order('nid DESC')
+              .limit(10)
+  revisions = Revision.joins(:node)
+                      .order('timestamp DESC')
+                      .where('type = (?)', 'page')
+                      .where('node.status = 1')
+                      .where('node_revisions.status = 1')
+                      .where('timestamp - node.created > ?', 300) # don't report edits within 5 mins of page creation
+                      .limit(10)
+                      .group('node.title')
+  # group by day: http://stackoverflow.com/questions/5970938/group-by-day-from-timestamp
+  revisions = revisions.group('DATE(FROM_UNIXTIME(timestamp))') if Rails.env == 'production'
+  revisions = revisions.to_a # ensure it can be serialized for caching
+  wikis += revisions
+  wikis = wikis.sort_by(&:created_at).reverse
+  comments = Comment.joins(:node, :drupal_user)
+                    .order('timestamp DESC')
+                    .where('timestamp - node.created > ?', 86_400) # don't report edits within 1 day of page creation
+                    .page(params[:page])
+                    .group('title') # group by day: http://stackoverflow.com/questions/5970938/group-by-day-from-timestamp
+  # group by day: http://stackoverflow.com/questions/5970938/group-by-day-from-timestamp
+  comments = comments.group('DATE(FROM_UNIXTIME(timestamp))') if Rails.env == 'production'
+  comments = comments.to_a # ensure it can be serialized for caching
+  answer_comments = Comment.joins(:answer, :drupal_user)
+                           .order('timestamp DESC')
+                           .where('timestamp - answers.created_at > ?', 86_400)
+                           .limit(20)
+                           .group('answers.id')
+  answer_comments = answer_comments.group('DATE(FROM_UNIXTIME(timestamp))') if Rails.env == 'production'
+  answer_comments = answer_comments.to_a # ensure it can be serialized for caching
+  activity = (notes + wikis + comments + answer_comments).sort_by(&:created_at).reverse
+  response = [
+    activity,
+    blog,
+    notes,
+    wikis,
+    revisions,
+    comments,
+    answer_comments
+  ]
+  response
+end
+
+ +
+ + + + +
+ + +
+ +
+ dashboard() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/home_controller.rb, line 50
+def dashboard
+  @note_count = Node.select(%[created type status])
+                    .where(type: 'note', status: 1, created: Time.now.to_i - 1.weeks.to_i..Time.now.to_i)
+                    .count(:all)
+  @wiki_count = Revision.select(:timestamp)
+                        .where(timestamp: Time.now.to_i - 1.weeks.to_i..Time.now.to_i)
+                        .count
+  @user_note_count = Node.where(type: 'note', status: 1, uid: current_user.uid).count if current_user
+  @activity, @blog, @notes, @wikis, @revisions, @comments, @answer_comments = self.activity
+  render template: 'dashboard/dashboard'
+  @title = I18n.t('home_controller.community_research') unless current_user
+end
+
+ +
+ + + + +
+ + +
+ +
+ dashboard2() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/home_controller.rb, line 46
+def dashboard2
+  redirect_to '/dashboard'
+end
+
+ +
+ + + + +
+ + +
+ +
+ fetch() + + click to toggle source + +
+ + +
+ +

proxy to enable AJAX loading of RSS feeds, which requires same-origin

+ + + + +
+
# File app/controllers/home_controller.rb, line 25
+def fetch
+  if true # Rails.env.production?
+    if params[:url][0..24] == 'https://groups.google.com' || params[:url] == 'https://feeds.feedburner.com/rssmixer/ZvcX'
+      url = URI.parse(params[:url])
+      result = Net::HTTP.get_response(url)
+      send_data result.body, type: result.content_type, disposition: 'inline'
+    end
+  else
+    redirect_to params[:url]
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ front() + + click to toggle source + +
+ + +
+ +

route for seeing the front page even if you are logged in

+ + + + +
+
# File app/controllers/home_controller.rb, line 38
+def front
+  @title = I18n.t('home_controller.environmental_investigation')
+  @activity, @blog, @notes, @wikis, @revisions, @comments, @answer_comments = Rails.cache.fetch("front-activity", expires_in: 30.minutes) do
+    self.activity
+  end
+  render template: 'home/home'
+end
+
+ +
+ + + + +
+ + +
+ +
+ home() + + click to toggle source + +
+ + +
+ +

caches_action :index, :cache_path => { :last => +Node.find(:last).updated_at.to_i }

+ + + + +
+
# File app/controllers/home_controller.rb, line 11
+def home
+  @activity, @blog, @notes, @wikis, @revisions, @comments, @answer_comments = Rails.cache.fetch("front-activity", expires_in: 30.minutes) do
+    self.activity
+  end
+
+  @title = I18n.t('home_controller.science_community')
+  if current_user
+    redirect_to '/dashboard'
+  else
+    render template: 'home/home'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ nearby() + + click to toggle source + +
+ + +
+ +

trashy… clean this up! this will eventually be based on the profile_tags +data where people can mark their location with “location:lat,lon”

+ + + + +
+
# File app/controllers/home_controller.rb, line 65
+def nearby
+  if current_user.lat
+    dist = 1.5
+    minlat = current_user.lat - dist
+    maxlat = current_user.lat + dist
+    minlon = current_user.lon - dist
+    maxlon = current_user.lon + dist
+    @users = DrupalUser.where('lat != 0.0 AND lon != 0.0 AND lat > ? AND lat < ? AND lon > ? AND lon < ?', minlat, maxlat, minlon, maxlon)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/HomeHelper.html b/doc/app/HomeHelper.html new file mode 100644 index 0000000000..28b00e1bd4 --- /dev/null +++ b/doc/app/HomeHelper.html @@ -0,0 +1,95 @@ + + + + + + +module HomeHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module HomeHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Image.html b/doc/app/Image.html new file mode 100644 index 0000000000..e38ab66684 --- /dev/null +++ b/doc/app/Image.html @@ -0,0 +1,263 @@ + + + + + + +class Image - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Image +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ filename() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/image.rb, line 45
+def filename
+  photo_file_name
+end
+
+ +
+ + + + +
+ + +
+ +
+ filetype() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/image.rb, line 32
+def filetype
+  filename[-3..filename.length].downcase
+end
+
+ +
+ + + + +
+ + +
+ +
+ is_image?() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/image.rb, line 28
+def is_image?
+  (filetype == 'jpg' || filetype == 'jpeg' || filetype == 'gif' || filetype == 'png')
+end
+
+ +
+ + + + +
+ + +
+ +
+ path(size = :medium) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/image.rb, line 36
+def path(size = :medium)
+  if is_image?
+    size = :medium if size == :default
+  else
+    size = :original
+  end
+  absolute_uri + photo.url(size)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/ImagesController.html b/doc/app/ImagesController.html new file mode 100644 index 0000000000..1f856bf519 --- /dev/null +++ b/doc/app/ImagesController.html @@ -0,0 +1,258 @@ + + + + + + +class ImagesController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class ImagesController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/images_controller.rb, line 7
+def create
+  if params[:i]
+    @image = Image.new(remote_url: params[:i],
+                       uid: current_user.uid)
+    flash[:error] = 'The image could not be saved.' unless @image.save!
+  else
+    @image = Image.new(uid: current_user.uid,
+                       photo: params[:image][:photo],
+                       title: params[:image][:title],
+                       notes: params[:image][:notes])
+  end
+  @image.nid = Node.find(params[:nid].to_i).nid unless params[:nid].nil? || params[:nid] == 'undefined'
+  if @image.save!
+    render json: {
+      id:       @image.id,
+      url:      @image.path(:large),
+      filename: @image.photo_file_name,
+      href:     @image.path(:large), # Woofmark/PublicLab.Editor
+      title:    @image.photo_file_name,
+      results:  [{ # Woofmark/PublicLab.Editor
+        href:  @image.path(:large),
+        title: @image.photo_file_name
+      }]
+    }
+  else
+    render text: 'The image could not be saved.'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/images_controller.rb, line 40
+def delete
+  @image = Image.find params[:id]
+  if @image.uid == current_user.uid # or current_user.role == "admin"
+    if @image.delete
+      flash[:notice] = 'Image deleted.'
+    else
+      flash[:error] = 'The image could not be deleted.'
+    end
+    redirect_to '/post'
+  else
+    prompt_login 'Only the owner can delete this image.'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/images_controller.rb, line 36
+def new
+  @image = Image.new
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/LegacyController.html b/doc/app/LegacyController.html new file mode 100644 index 0000000000..8d5463c33a --- /dev/null +++ b/doc/app/LegacyController.html @@ -0,0 +1,587 @@ + + + + + + +class LegacyController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class LegacyController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ file() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 39
+def file
+  redirect_to "//#{request.host}/sites/default/files/" + params[:filename] + '.' + params[:format], status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ node() + + click to toggle source + +
+ + +
+ +

publiclaboratory.org/node/5853

+ + + + +
+
# File app/controllers/legacy_controller.rb, line 53
+def node
+  node = Node.find params[:id]
+  redirect_to node.path, status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ note_add() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 10
+def note_add
+  redirect_to '/post', status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 2
+def notes
+  if params[:id]
+    redirect_to '/tag/' + params[:id], status: 301
+  else
+    redirect_to '/research', status: 301
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ openid() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 30
+def openid
+  user = User.find params[:id]
+  redirect_to '/openid/' + user.username, status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ openid_username() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 35
+def openid_username
+  redirect_to '/openid/' + params[:username], status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ page_add() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 14
+def page_add
+  redirect_to '/wiki/new', status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ people() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 18
+def people
+  redirect_to '/profile/' + params[:id], status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ place() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 22
+def place
+  redirect_to '/wiki/' + params[:id], status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ register() + + click to toggle source + +
+ + +
+ +

def image

+ +
# sites/default/files/imagecache/thumb/san-martin-spectro.jpg
+redirect_to "//i.publiclab.org/sites/default/files/imagecache/"+params[:size]+"/"+params[:filename]+"."+params[:format], :status => 301
+
+ +

end

+ + + + +
+
# File app/controllers/legacy_controller.rb, line 48
+def register
+  redirect_to '/signup', status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ report() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 58
+def report
+  @node = DrupalUrlAlias.find_by(dst: 'report/' + params[:id]).node
+  redirect_to '/notes/' + @node.author.name.downcase + '/' + Time.at(@node.created_at).strftime('%m-%d-%Y') + '/' + params[:id], status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ rss() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 63
+def rss
+  redirect_to '/feed.rss', status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+ tool() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/legacy_controller.rb, line 26
+def tool
+  redirect_to '/wiki/' + params[:id], status: 301
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/LikeController.html b/doc/app/LikeController.html new file mode 100644 index 0000000000..5c48b3a3e8 --- /dev/null +++ b/doc/app/LikeController.html @@ -0,0 +1,301 @@ + + + + + + +class LikeController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class LikeController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ +

for the current user, register as liking the given node

+ + + + +
+
# File app/controllers/like_controller.rb, line 29
+def create
+  render json: Node.like(params[:id] , current_user)
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ +

for the current user, remove the like from the given node

+ + + + +
+
# File app/controllers/like_controller.rb, line 34
+def delete
+  render json: Node.unlike(params[:id] , current_user)
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ +

list all recent likes

+ + + + +
+
# File app/controllers/like_controller.rb, line 6
+def index
+  @paginated = true
+  @likes = NodeSelection.all.reverse.paginate(page: params[:page])
+end
+
+ +
+ + + + +
+ + +
+ +
+ liked?() + + click to toggle source + +
+ + +
+ +

for the current user, return whether is presently liked or not

+ + + + +
+
# File app/controllers/like_controller.rb, line 18
+def liked?
+  result = NodeSelection.find_by_user_id_and_nid(current_user.uid, params[:id])
+  result = if result.nil?
+             false
+           else
+             result.liking
+           end
+  render json: result
+end
+
+ +
+ + + + +
+ + +
+ +
+ show() + + click to toggle source + +
+ + +
+ +

return a count of likes for a given node This does not support non-nodes +very well

+ + + + +
+
# File app/controllers/like_controller.rb, line 13
+def show
+  render json: Node.find(params[:id]).cached_likes
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/MapController.html b/doc/app/MapController.html new file mode 100644 index 0000000000..7e6d9bb9b5 --- /dev/null +++ b/doc/app/MapController.html @@ -0,0 +1,579 @@ + + + + + + +class MapController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class MapController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ +

must require min_zoom and lat/lon location, and TMS URL solving this by +min_zoom default here, but need better solution

+ + + + +
+
# File app/controllers/map_controller.rb, line 127
+def create
+  if current_user && current_user.role == 'admin'
+    saved, @node, @revision = Node.new_node(uid: current_user.uid,
+                                            title: params[:title],
+                                            body: params[:body],
+                                            type: 'map',
+                                            main_image: params[:main_image])
+
+    if saved
+      if params[:tags]
+        params[:tags].split(',').each do |tagname|
+          @node.add_tag(tagname, current_user)
+        end
+      end
+
+      # save main image
+      if params[:main_image] && params[:main_image] != ''
+        img = Image.find params[:main_image]
+        unless img.nil?
+          img.nid = @node.id
+          img.save
+        end
+      end
+
+      @node.add_tag('lat:' + params[:lat], current_user)
+      @node.add_tag('lon:' + params[:lon], current_user)
+
+      map = DrupalContentTypeMap.new
+      map.nid = @node.nid
+      map.vid = @node.nid
+
+      map.field_publication_date_value    = params[:map][:field_publication_date_value]
+      map.field_capture_date_value        = params[:map][:field_capture_date_value]
+      map.field_geotiff_url_value         = params[:map][:field_geotiff_url_value]
+      map.field_google_maps_url_value     = params[:map][:field_google_maps_url_value]
+      map.field_openlayers_url_value      = params[:map][:field_openlayers_url_value]
+      map.field_tms_url_value             = params[:map][:field_tms_url_value]
+      map.field_jpg_url_value             = params[:map][:field_jpg_url_value]
+      map.field_license_value             = params[:map][:field_license_value]
+      map.field_raw_images_value          = params[:map][:field_raw_images_value]
+      map.field_cartographer_notes_value  = params[:map][:field_cartographer_notes_value]
+      map.field_notes_value               = params[:map][:field_notes_value]
+      map.field_mbtiles_url_value         = params[:map][:field_mbtiles_url_value]
+      map.field_zoom_min_value            = params[:map][:field_zoom_min_value]
+      map.field_zoom_min_value ||= 17
+      map.field_ground_resolution_value   = params[:map][:field_ground_resolution_value]
+      map.field_geotiff_filesize_value    = params[:map][:field_geotiff_filesize_value]
+      map.field_jpg_filesize_value        = params[:map][:field_jpg_filesize_value]
+      map.field_raw_images_filesize_value = params[:map][:field_raw_images_filesize_value]
+      map.field_tms_tile_type_value       = params[:map][:field_tms_tile_type_value]
+      map.field_zoom_max_value            = params[:map][:field_zoom_max_value]
+
+      # need to create/delete these. Maybe best just make a new field, no need to store individual records
+      # @node.drupal_content_field_map_editor
+      # @node.drupal_content_field_mappers.collect(&:field_mappers_value).uniq.join(', ')
+      map.authorship                      = params[:map][:authorship]
+
+      ActiveRecord::Base.transaction do # in case only part of this completes
+        if @node.save && @revision.save && map.save
+          flash[:notice] = 'Edits saved.'
+          redirect_to @node.path
+        else
+          flash[:error] = 'Your edit could not be saved.'
+          render action: :edit
+        end
+      end
+    else
+      flash[:error] = 'Your edit could not be saved.'
+      render template: 'map/edit'
+    end
+  else
+    prompt_login 'Only admins can publish maps at this time.'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/map_controller.rb, line 39
+def delete
+  @node = Node.find_by(id: params[:id])
+  if current_user.uid == @node.uid || current_user.role == 'admin'
+    @node.delete
+    flash[:notice] = 'Content deleted.'
+    redirect_to '/archive'
+  else
+    prompt_login 'Only admins can edit maps at this time.'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ edit() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/map_controller.rb, line 30
+def edit
+  @node = Node.find_by(id: params[:id])
+  if current_user.uid == @node.uid || current_user.role == 'admin'
+    render template: 'map/edit'
+  else
+    prompt_login 'Only admins can edit maps at this time.'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/map_controller.rb, line 2
+def index
+  @title = 'Maps'
+  @nodes = Node.paginate(page: params[:page], per_page: 32)
+               .order('nid DESC')
+               .where(type: 'map', status: 1)
+
+  # I'm not sure if this is actually eager loading the tags...
+  @maps = Node.joins(:tag)
+              .where('type = "map" AND status = 1 AND (term_data.name LIKE ? OR term_data.name LIKE ?)', 'lat:%', 'lon:%')
+              .uniq
+
+  # This is supposed to eager load the url_aliases, and seems to run, but doesn't actually eager load them...?
+  # @maps = Node.select("node.*,url_alias.dst AS dst").joins(:tag).where('type = "map" AND status = 1 AND (term_data.name LIKE ? OR term_data.name LIKE ?)', 'lat:%', 'lon:%').joins("INNER JOIN url_alias ON url_alias.src = CONCAT('node/',node.nid)")
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/map_controller.rb, line 116
+def new
+  if current_user && current_user.role == 'admin'
+    @node = Node.new(type: 'map')
+    render template: 'map/edit'
+  else
+    prompt_login 'Only admins can publish maps at this time.'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ show() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/map_controller.rb, line 17
+def show
+  @node = Node.find_map(params[:name], params[:date])
+
+  # redirect_old_urls
+
+  impressionist(@node)
+  @title = @node.title
+  @tags = @node.tags
+  @tagnames = @tags.collect(&:name)
+
+  set_sidebar :tags, @tagnames
+end
+
+ +
+ + + + +
+ + +
+ +
+ tag() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/map_controller.rb, line 202
+def tag
+  set_sidebar :tags, [params[:id]], note_count: 20
+
+  @tagnames = params[:id].split(',')
+  nids = Tag.find_nodes_by_type(params[:id], 'map', 20).collect(&:nid)
+  @notes = Node.paginate(page: params[:page])
+               .where('nid in (?)', nids)
+               .order('nid DESC')
+
+  @title = @tagnames.join(', ') if @tagnames
+  @unpaginated = true
+  render template: 'tag/show'
+end
+
+ +
+ + + + +
+ + +
+ +
+ update() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/map_controller.rb, line 50
+def update
+  @node = Node.find_by(id: params[:id])
+  if current_user.uid == @node.uid || current_user.role == 'admin'
+
+    @node.title = params[:title]
+    @revision = @node.latest
+    @revision.title = params[:title]
+    @revision.body = params[:body]
+
+    if params[:tags]
+      params[:tags].split(',').each do |tagname|
+        @node.add_tag(tagname, current_user)
+      end
+    end
+
+    # save main image
+    if params[:main_image] && params[:main_image] != ''
+      img = Image.find params[:main_image]
+      unless img.nil?
+        img.nid = @node.id
+        img.save
+      end
+    end
+
+    @node.add_tag('lat:' + params[:lat], current_user)
+    @node.add_tag('lon:' + params[:lon], current_user)
+
+    map = @node.map
+    map.field_publication_date_value    = params[:map][:field_publication_date_value]
+    map.field_capture_date_value        = params[:map][:field_capture_date_value]
+    map.field_geotiff_url_value         = params[:map][:field_geotiff_url_value]
+    map.field_google_maps_url_value     = params[:map][:field_google_maps_url_value]
+    map.field_openlayers_url_value      = params[:map][:field_openlayers_url_value]
+    map.field_tms_url_value             = params[:map][:field_tms_url_value]
+    map.field_jpg_url_value             = params[:map][:field_jpg_url_value]
+    map.field_license_value             = params[:map][:field_license_value]
+    map.field_raw_images_value          = params[:map][:field_raw_images_value]
+    map.field_cartographer_notes_value  = params[:map][:field_cartographer_notes_value]
+    map.field_notes_value               = params[:map][:field_notes_value]
+    map.field_mbtiles_url_value         = params[:map][:field_mbtiles_url_value]
+    map.field_zoom_min_value            = params[:map][:field_zoom_min_value]
+    map.field_ground_resolution_value   = params[:map][:field_ground_resolution_value]
+    map.field_geotiff_filesize_value    = params[:map][:field_geotiff_filesize_value]
+    map.field_jpg_filesize_value        = params[:map][:field_jpg_filesize_value]
+    map.field_raw_images_filesize_value = params[:map][:field_raw_images_filesize_value]
+    map.field_tms_tile_type_value       = params[:map][:field_tms_tile_type_value]
+    map.field_zoom_max_value            = params[:map][:field_zoom_max_value]
+
+    # need to create/delete these. Maybe best just make a new field, no need to store individual records
+    # @node.drupal_content_field_map_editor
+    # @node.drupal_content_field_mappers.collect(&:field_mappers_value).uniq.join(', ')
+    # combined record as string:
+    map.authorship                      = params[:map][:authorship]
+
+    if @node.save && @revision.save && map.save
+      flash[:notice] = 'Edits saved.'
+      redirect_to @node.path
+    else
+      flash[:error] = 'Your edit could not be saved.'
+      render action: :edit
+    end
+  else
+    prompt_login 'Only admins can edit maps at this time.'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/MapHelper.html b/doc/app/MapHelper.html new file mode 100644 index 0000000000..5064629bbd --- /dev/null +++ b/doc/app/MapHelper.html @@ -0,0 +1,95 @@ + + + + + + +module MapHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module MapHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Node.html b/doc/app/Node.html new file mode 100644 index 0000000000..10d9ab5bec --- /dev/null +++ b/doc/app/Node.html @@ -0,0 +1,3574 @@ + + + + + + +class Node - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Node +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ activities(tagname) + + click to toggle source + +
+ + +
+ +

so we can call #activities('balloon-mapping')

+ + + + +
+
# File app/models/node.rb, line 752
+def self.activities(tagname)
+  Node.where(status: 1, type: 'note')
+      .includes(:revision, :tag)
+      .references(:term_data)
+      .where('term_data.name LIKE ?', "activity:#{tagname}")
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_by_path(title) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 462
+def self.find_by_path(title)
+  Node.where(path: ["/#{title}"]).first
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_map(name, date) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 694
+def self.find_map(name, date)
+  Node.where(path: "/map/#{name}/#{date}").first
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_notes(author, date, title) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 690
+def self.find_notes(author, date, title)
+  Node.where(path: "/notes/#{author}/#{date}/#{title}").first
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_wiki(title) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 698
+def self.find_wiki(title)
+  Node.where(path: ["/#{title}", "/tool/#{title}", "/wiki/#{title}", "/place/#{title}"]).first
+end
+
+ +
+ + + + +
+ + +
+ +
+ inheritance_column() + + click to toggle source + +
+ + +
+ +

making drupal and rails database conventions play nice; 'type' is a +reserved word in rails

+ + + + +
+
# File app/models/node.rb, line 67
+def self.inheritance_column
+  'rails_type'
+end
+
+ +
+ + + + +
+ + +
+ +
+ instance_method_already_implemented?(method_name) + + click to toggle source + +
+ + +
+ + + + +
+ Calls superclass method + +
+ + + +
+
# File app/models/node.rb, line 58
+def instance_method_already_implemented?(method_name)
+  return true if method_name == 'changed'
+  return true if method_name == 'changed?'
+  super
+end
+
+ +
+ + + + +
+ + +
+ +
+ like(nid , user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 825
+def self.like(nid , user)
+   # scope like variable outside the transaction
+  like = nil
+  count = nil
+
+  ActiveRecord::Base.transaction do
+    # Create the entry if it isn't already created.
+    like = NodeSelection.where(user_id: user.uid,
+                               nid: nid).first_or_create
+    like.liking = true
+    node = Node.find(nid)       
+    if node.type == 'note'
+      SubscriptionMailer.notify_note_liked(node, like.user)
+    end
+    count = 1
+    node.toggle_like(like.user)
+    # Save the changes.
+    node.save!
+    like.save!
+  end
+    count
+end
+
+ +
+ + + + +
+ + +
+ +
+ new_node(params) + + click to toggle source + +
+ + +
+ +

same as ::new_note or ::new_wiki but with arbitrary type – +use for maps, DRY out ::new_note +and ::new_wiki

+ + + + +
+
# File app/models/node.rb, line 609
+def self.new_node(params)
+  saved = false
+  node = Node.new(uid: params[:uid],
+                  title: params[:title],
+                  type: params[:type])
+  if node.valid?
+    revision = false
+    saved = true
+    ActiveRecord::Base.transaction do
+      node.save!
+      revision = node.new_revision(nid: node.id,
+                                   uid: params[:uid],
+                                   title: params[:title],
+                                   body: params[:body])
+      if revision.valid?
+        revision.save!
+        node.vid = revision.vid
+        node.save!
+      else
+        saved = false
+        node.destroy # clean up
+      end
+    end
+  end
+  [saved, node, revision]
+end
+
+ +
+ + + + +
+ + +
+ +
+ new_note(params) + + click to toggle source + +
+ + +
+ +

handle creating a new note with attached revision and main image this is +kind of egregiously bad… must revise after researching simultaneous +creation of associated records

+ + + + +
+
# File app/models/node.rb, line 544
+def self.new_note(params)
+  saved = false
+  author = DrupalUser.find(params[:uid])
+  node = Node.new(uid:     author.uid,
+                  title:   params[:title],
+                  comment: 2,
+                  type:    'note')
+  node.status = 4 if author.first_time_poster
+  if node.valid? # is this not triggering title uniqueness validation?
+    saved = true
+    revision = false
+    ActiveRecord::Base.transaction do
+      node.save!
+      revision = node.new_revision(uid:   author.uid,
+                                   title: params[:title],
+                                   body:  params[:body])
+      if revision.valid?
+        revision.save!
+        node.vid = revision.vid
+        # save main image
+        if params[:main_image] && (params[:main_image] != '')
+          img = Image.find params[:main_image]
+          img.nid = node.id
+          img.save
+        end
+        node.save!
+        node.notify
+      else
+        saved = false
+        node.destroy
+      end
+    end
+  end
+  [saved, node, revision]
+end
+
+ +
+ + + + +
+ + +
+ +
+ new_wiki(params) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 580
+def self.new_wiki(params)
+  saved = false
+  node = Node.new(uid: params[:uid],
+                  title: params[:title],
+                  type: 'page')
+  if node.valid?
+    revision = false
+    saved = true
+    ActiveRecord::Base.transaction do
+      node.save!
+      revision = node.new_revision(nid: node.id,
+                                   uid: params[:uid],
+                                   title: params[:title],
+                                   body: params[:body])
+      if revision.valid?
+        revision.save!
+        node.vid = revision.vid
+        node.save!
+        # node.notify # we don't yet notify of wiki page creations
+      else
+        saved = false
+        node.destroy # clean up
+      end
+    end
+  end
+  [saved, node, revision]
+end
+
+ +
+ + + + +
+ + +
+ +
+ questions() + + click to toggle source + +
+ + +
+ +

all questions

+ + + + +
+
# File app/models/node.rb, line 732
+def self.questions
+  questions = Node.where(type: 'note')
+                  .joins(:tag)
+                  .where('term_data.name LIKE ?', 'question:%')
+                  .group('node.nid')
+end
+
+ +
+ + + + +
+ + +
+ +
+ research_notes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 702
+def self.research_notes
+  nids = Node.where(type: 'note')
+             .joins(:tag)
+             .where('term_data.name LIKE ?', 'question:%')
+             .group('node.nid')
+             .collect(&:nid)
+  notes = Node.where(type: 'note')
+              .where('node.nid NOT IN (?)', nids)
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+ unlike(nid , user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 848
+def self.unlike(nid , user)
+  like = nil
+  count = nil
+
+  ActiveRecord::Base.transaction do
+    like = NodeSelection.where(user_id: user.uid,
+                               nid: nid).first_or_create
+    like.liking = false
+    count = -1 
+    node = Node.find(nid)       
+    node.toggle_like(like.user)
+    node.save!
+    like.save!
+   end 
+    count
+end
+
+ +
+ + + + +
+ + +
+ +
+ upgrades(tagname) + + click to toggle source + +
+ + +
+ +

so we can call #upgrades('balloon-mapping')

+ + + + +
+
# File app/models/node.rb, line 772
+def self.upgrades(tagname)
+  Node.where(status: 1, type: 'note')
+      .includes(:revision, :tag)
+      .references(:term_data)
+      .where('term_data.name LIKE ?', "upgrade:#{tagname}")
+end
+
+ +
+ + + + +
+ + +
+ +
+ weekly_tallies(type = 'note', span = 52, time = Time.now) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 132
+def self.weekly_tallies(type = 'note', span = 52, time = Time.now)
+  weeks = {}
+  (0..span).each do |week|
+    weeks[span - week] = Node.select(:created)
+                             .where(type:    type,
+                                    status:  1,
+                                    created: time.to_i - week.weeks.to_i..time.to_i - (week - 1).weeks.to_i)
+                             .count
+  end
+  weeks
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ activities() + + click to toggle source + +
+ + +
+ +

so we can quickly fetch activities corresponding to this node with +node.activities

+ + + + +
+
# File app/models/node.rb, line 741
+def activities
+  # override with a tag like `activities:h2s`
+  if self.has_power_tag('activities')
+    tagname = node.power_tag('activities')
+  else
+    tagname = self.slug_from_path
+  end
+  Node.activities(tagname)
+end
+
+ +
+ + + + +
+ + +
+ +
+ add_barnstar(tagname, giver) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 644
+def add_barnstar(tagname, giver)
+  add_tag(tagname, giver.drupal_user)
+  CommentMailer.notify_barnstar(giver, self)
+end
+
+ +
+ + + + +
+ + +
+ +
+ add_comment(params = {}) + + click to toggle source + +
+ + +
+ +
+ +

Automated constructors for associated models

+ + + + +
+
# File app/models/node.rb, line 513
+def add_comment(params = {})
+  thread = if !comments.empty? && !comments.last.nil?
+             comments.last.next_thread
+           else
+             '01/'
+           end
+  c = Comment.new(pid: 0,
+                  nid: nid,
+                  uid: params[:uid],
+                  subject: '',
+                  hostname: '',
+                  comment: params[:body],
+                  status: 0,
+                  format: 1,
+                  thread: thread,
+                  timestamp: DateTime.now.to_i)
+  c.save
+  c
+end
+
+ +
+ + + + +
+ + +
+ +
+ add_tag(tagname, user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 649
+def add_tag(tagname, user)
+  tagname = tagname.downcase
+  unless has_tag_without_aliasing(tagname)
+    saved = false
+    tag = Tag.find_by(name: tagname) || Tag.new(vid:         3, # vocabulary id; 1
+                                                name:        tagname,
+                                                description: '',
+                                                weight:      0)
+
+    ActiveRecord::Base.transaction do
+      if tag.valid?
+        if tag.name.split(':')[0] == 'date'
+          begin
+            DateTime.strptime(tag.name.split(':')[1], '%m-%d-%Y').to_date.to_s(:long)
+          rescue
+            return [false, tag.destroy]
+          end
+        end
+        tag.save!
+        node_tag = NodeTag.new(tid: tag.id,
+                               uid: user.uid,
+                               date: DateTime.now.to_i,
+                               nid: id)
+        if node_tag.save
+          saved = true
+          SubscriptionMailer.notify_tag_added(self, tag, user) unless tag.subscriptions.empty?
+        else
+          saved = false
+          tag.destroy
+        end
+      end
+    end
+    return [saved, tag]
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ answered() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 168
+def answered
+  self.answers && self.answers.length > 0
+end
+
+ +
+ + + + +
+ + +
+ +
+ author() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 207
+def author
+  DrupalUser.find_by(uid: uid)
+end
+
+ +
+ + + + +
+ + +
+ +
+ authors() + + click to toggle source + +
+ + +
+ +

for wikis:

+ + + + +
+
# File app/models/node.rb, line 216
+def authors
+  revisions.collect(&:author).uniq
+end
+
+ +
+ + + + +
+ + +
+ +
+ barnstar() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 636
+def barnstar
+  power_tag_objects('barnstar').first
+end
+
+ +
+ + + + +
+ + +
+ +
+ barnstars() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 640
+def barnstars
+  power_tag_objects('barnstar')
+end
+
+ +
+ + + + +
+ + +
+ +
+ body() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 244
+def body
+  latest.body if latest
+end
+
+ +
+ + + + +
+ + +
+ +
+ body_preview(length = 100) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 712
+def body_preview(length = 100)
+  try(:latest).body_preview(length)
+end
+
+ +
+ + + + +
+ + +
+ +
+ can_tag(tagname, user, errors = false) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 779
+def can_tag(tagname, user, errors = false)
+  if tagname[0..4] == 'with:'
+    if User.find_by_username_case_insensitive(tagname.split(':')[1]).nil?
+      errors ? I18n.t('node.cannot_find_username') : false
+    elsif author.uid != user.uid
+      errors ? I18n.t('node.only_author_use_powertag') : false
+    elsif tagname.split(':')[1] == user.username
+      errors ? I18n.t('node.cannot_add_yourself_coauthor') : false
+    else
+      true
+    end
+  elsif tagname[0..4] == 'rsvp:' && user.username != tagname.split(':')[1]
+    errors ? I18n.t('node.only_RSVP_for_yourself') : false
+  elsif tagname == 'locked' && user.role != 'admin'
+    errors ? I18n.t('node.only_admins_can_lock') : false
+  elsif tagname.split(':')[0] == 'redirect' && Node.where(slug: tagname.split(':')[1]).length <= 0
+    errors ? I18n.t('node.page_does_not_exist') : false
+  else
+    true
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ coauthors() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 211
+def coauthors
+  User.where(username: power_tags('with')) if has_power_tag('with')
+end
+
+ +
+ + + + +
+ + +
+ +
+ comment_count() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 202
+def comment_count
+  comments
+    .count
+end
+
+ +
+ + + + +
+ + +
+ +
+ created_at() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 236
+def created_at
+  Time.at(created)
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+ drupal_main_image() + + click to toggle source + +
+ + +
+ +

was unable to set up this relationship properly with ActiveRecord associations

+ + + + +
+
# File app/models/node.rb, line 249
+def drupal_main_image
+  DrupalMainImage.order('vid')
+                 .where('nid = ? AND field_main_image_fid IS NOT NULL', nid)
+                 .last
+end
+
+ +
+ + + + +
+ + +
+ +
+ edit_path() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 453
+def edit_path
+  path = if type == 'page' || type == 'tool' || type == 'place'
+           '/wiki/edit/' + self.path.split('/').last
+         else
+           '/notes/edit/' + id.to_s
+         end
+  path
+end
+
+ +
+ + + + +
+ + +
+ +
+ files() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 164
+def files
+  drupal_files
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+ generate_path() + + click to toggle source + +
+ + +
+ +

should only be run at actual creation time – or, we should refactor to us +node.created instead of Time.now

+ + + + +
+
# File app/models/node.rb, line 91
+def generate_path
+  if type == 'note'
+    username = DrupalUser.find_by(uid: uid).name
+    "/notes/#{username}/#{Time.now.strftime('%m-%d-%Y')}/#{title.parameterize}"
+  elsif type == 'page'
+    '/wiki/' + title.parameterize
+  elsif type == 'map'
+    "/map/#{title.parameterize}/#{Time.now.strftime('%m-%d-%Y')}"
+  elsif type == 'feature'
+    "/feature/#{title.parameterize}"
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ get_matching_tags_without_aliasing(tagname) + + click to toggle source + +
+ + +
+ +

can return multiple Tag records – we don't yet +hard-enforce uniqueness, but should soon then, this would just be replaced +by Tag.where(name: tagname).first

+ + + + +
+
# File app/models/node.rb, line 389
+def get_matching_tags_without_aliasing(tagname)
+  tags = Tag.includes(:node_tag)
+            .references(:community_tags)
+            .where('community_tags.nid = ? AND name LIKE ?', id, tagname)
+  # search for tags which end in wildcards
+  if tagname[-1] == '*'
+    tags += Tag.includes(:node_tag)
+               .references(:community_tags)
+               .where('community_tags.nid = ? AND (name LIKE ? OR name LIKE ?)', id, tagname, tagname.tr('*', '%'))
+  end
+  tags
+end
+
+ +
+ + + + +
+ + +
+ +
+ has_accepted_answers() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 172
+def has_accepted_answers
+  self.answers.where(accepted: true).count > 0
+end
+
+ +
+ + + + +
+ + +
+ +
+ has_mailing_list?() + + click to toggle source + +
+ + +
+ +
+ +

Tag-related methods

+ + + + +
+
# File app/models/node.rb, line 285
+def has_mailing_list?
+  has_power_tag('list')
+end
+
+ +
+ + + + +
+ + +
+ +
+ has_power_tag(key) + + click to toggle source + +
+ + +
+ +

power tags have “key:value” format, and should be searched with a “key:*” +wildcard

+ + + + +
+
# File app/models/node.rb, line 312
+def has_power_tag(key)
+  tids = Tag.includes(:node_tag)
+            .references(:community_tags)
+            .where('community_tags.nid = ? AND name LIKE ?', id, key + ':%')
+            .collect(&:tid)
+  !NodeTag.where('nid = ? AND tid IN (?)', id, tids).empty?
+end
+
+ +
+ + + + +
+ + +
+ +
+ has_tag(tagname) + + click to toggle source + +
+ + +
+ +

accests a tagname /or/ tagname ending in wildcard such as “tagnam*” also +searches for other tags whose parent field matches given tagname, but not +tags matching given tag's parent field

+ + + + +
+
# File app/models/node.rb, line 370
+def has_tag(tagname)
+  tags = get_matching_tags_without_aliasing(tagname)
+  # search for tags with parent matching this
+  tags += Tag.includes(:node_tag)
+             .references(:community_tags)
+             .where('community_tags.nid = ? AND parent LIKE ?', id, tagname)
+  # search for parent tag of this, if exists
+  # tag = Tag.where(name: tagname).try(:first)
+  # if tag && tag.parent
+  #  tags += Tag.includes(:node_tag)
+  #             .references(:community_tags)
+  #             .where("community_tags.nid = ? AND name LIKE ?", self.id, tag.parent)
+  # end
+  tids = tags.collect(&:tid).uniq
+  !NodeTag.where('nid IN (?) AND tid IN (?)', id, tids).empty?
+end
+
+ +
+ + + + +
+ + +
+ +
+ has_tag_without_aliasing(tagname) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 402
+def has_tag_without_aliasing(tagname)
+  tags = get_matching_tags_without_aliasing(tagname)
+  tids = tags.collect(&:tid).uniq
+  !NodeTag.where('nid IN (?) AND tid IN (?)', id, tids).empty?
+end
+
+ +
+ + + + +
+ + +
+ +
+ icon() + + click to toggle source + +
+ + +
+ +

used in typeahead autocomplete search results

+ + + + +
+
# File app/models/node.rb, line 420
+def icon
+  icon = 'file' if type == 'note'
+  icon = 'book' if type == 'page'
+  icon = 'map-marker' if type == 'map'
+  icon = 'flag' if has_tag('chapter')
+  icon = 'wrench' if type == 'tool'
+  icon = 'question-circle' if has_power_tag('question')
+  icon
+end
+
+ +
+ + + + +
+ + +
+ +
+ id() + + click to toggle source + +
+ + +
+ +

view adaptors for typical rails db conventions so we can migrate someday

+ + + + +
+
# File app/models/node.rb, line 232
+def id
+  nid
+end
+
+ +
+ + + + +
+ + +
+ +
+ is_liked_by(user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 812
+def is_liked_by(user)
+   !NodeSelection.where(user_id: user.uid, nid: self.id , liking: true).empty?
+end
+
+ +
+ + + + +
+ + +
+ +
+ lat() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 472
+def lat
+  if has_power_tag('lat')
+    power_tag('lat').to_f
+  else
+    false
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ latest() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 186
+def latest
+  revisions
+    .where(status: 1)
+    .first
+end
+
+ +
+ + + + +
+ + +
+ +
+ likers() + + click to toggle source + +
+ + +
+ +

users who like this node

+ + + + +
+
# File app/models/node.rb, line 177
+def likers
+  node_selections
+    .joins(:drupal_user)
+    .references(:users)
+    .where(liking: true)
+    .where('users.status = ?', 1)
+    .collect(&:user)
+end
+
+ +
+ + + + +
+ + +
+ +
+ lon() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 480
+def lon
+  if has_power_tag('lon')
+    power_tag('lon').to_f
+  else
+    false
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ mailing_list() + + click to toggle source + +
+ + +
+ +

has it been tagged with “list:foo” where “foo” is the name of a Google +Group?

+ + + + +
+
# File app/models/node.rb, line 409
+def mailing_list
+  Rails.cache.fetch('feed-' + id.to_s + '-' + (updated_at.to_i / 300).to_i.to_s) do
+    RSS::Parser.parse(open('https://groups.google.com/group/' + power_tag('list') + '/feed/rss_v2_0_topics.xml').read, false).items
+  end
+rescue
+  return []
+end
+
+ +
+ + + + +
+ + +
+ +
+ main_image(node_type = :all) + + click to toggle source + +
+ + +
+ +

provide either a Drupally #main_image or a Railsy one

+ + + + +
+
# File app/models/node.rb, line 256
+def main_image(node_type = :all)
+  if !images.empty? && node_type != :drupal
+    if main_image_id.blank?
+      images.order('vid').last
+    else
+      images.where(id: main_image_id).first
+    end
+  elsif drupal_main_image && node_type != :rails
+    drupal_main_image.drupal_file
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ map() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 466
+def map
+  # This fires off a query that orders by vid DESC
+  # and is quicker than doing .order(vid: :DESC) for some reason.
+  drupal_content_type_map.last
+end
+
+ +
+ + + + +
+ + +
+ +
+ mentioned_users() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 685
+def mentioned_users
+  usernames = body.scan(Callouts.const_get(:FINDER))
+  User.where(username: usernames.map { |m| m[1] }).uniq
+end
+
+ +
+ + + + +
+ + +
+ +
+ new_revision(params) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 533
+def new_revision(params)
+  title = params[:title] || self.title
+  Revision.new(nid: id,
+               uid: params[:uid],
+               title: title,
+               body: params[:body])
+end
+
+ +
+ + + + +
+ + +
+ +
+ next_by_author() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 498
+def next_by_author
+  Node.where('uid = ? and nid > ? and type = "note"', author.uid, nid)
+      .order('nid')
+      .first
+end
+
+ +
+ + + + +
+ + +
+ +
+ node_tags() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 434
+def node_tags
+  node_tag
+end
+
+ +
+ + + + +
+ + +
+ +
+ normal_tags() + + click to toggle source + +
+ + +
+ +

return whole community_tag objects but no powertags or “event”

+ + + + +
+
# File app/models/node.rb, line 359
+def normal_tags
+  tids = Tag.includes(:node_tag)
+            .references(:community_tags)
+            .where('community_tags.nid = ? AND name LIKE ?', id, '%:%')
+            .collect(&:tid)
+  NodeTag.where('nid = ? AND tid NOT IN (?)', id, tids)
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 144
+def notify
+  if status == 4
+    AdminMailer.notify_node_moderators(self)
+  else
+    SubscriptionMailer.notify_node_creation(self)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ path(type = :default) + + click to toggle source + +
+ + +
+ +

can switch to a “question-style” path if specified

+ + + + +
+
# File app/models/node.rb, line 80
+def path(type = :default)
+  if type == :question
+    self[:path].gsub('/notes/', '/questions/')
+  else
+    # default path
+    self[:path]
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ power_tag(tag) + + click to toggle source + +
+ + +
+ +

returns the value for the most recent power tag of form key:value

+ + + + +
+
# File app/models/node.rb, line 321
+def power_tag(tag)
+  tids = Tag.includes(:node_tag)
+            .references(:community_tags)
+            .where('community_tags.nid = ? AND name LIKE ?', id, tag + ':%')
+            .collect(&:tid)
+  node_tag = NodeTag.where('nid = ? AND tid IN (?)', id, tids)
+                                   .order('nid DESC')
+  if node_tag && node_tag.first
+    node_tag.first.tag.name.gsub(tag + ':', '')
+  else
+    ''
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ power_tag_objects(tag) + + click to toggle source + +
+ + +
+ +

returns all power tag results as whole community_tag objects

+ + + + +
+
# File app/models/node.rb, line 350
+def power_tag_objects(tag)
+  tids = Tag.includes(:node_tag)
+            .references(:community_tags)
+            .where('community_tags.nid = ? AND name LIKE ?', id, tag + ':%')
+            .collect(&:tid)
+  NodeTag.where('nid = ? AND tid IN (?)', id, tids)
+end
+
+ +
+ + + + +
+ + +
+ +
+ power_tags(tag) + + click to toggle source + +
+ + +
+ +

returns all tagnames for a given power tag

+ + + + +
+
# File app/models/node.rb, line 336
+def power_tags(tag)
+  tids = Tag.includes(:node_tag)
+            .references(:community_tags)
+            .where('community_tags.nid = ? AND name LIKE ?', id, tag + ':%')
+            .collect(&:tid)
+  node_tags = NodeTag.where('nid = ? AND tid IN (?)', id, tids)
+  tags = []
+  node_tags.each do |nt|
+    tags << nt.name.gsub(tag + ':', '')
+  end
+  tags
+end
+
+ +
+ + + + +
+ + +
+ +
+ prev_by_author() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 504
+def prev_by_author
+  Node.where('uid = ? and nid < ? and type = "note"', author.uid, nid)
+      .order('nid desc')
+      .first
+end
+
+ +
+ + + + +
+ + +
+ +
+ publish() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 152
+def publish
+  self.status = 1
+  save
+  self
+end
+
+ +
+ + + + +
+ + +
+ +
+ questions() + + click to toggle source + +
+ + +
+ +

so we can quickly fetch questions corresponding to this node with +node.questions

+ + + + +
+
# File app/models/node.rb, line 718
+def questions
+  # override with a tag like `questions:h2s`
+  if self.has_power_tag('questions')
+    tagname = node.power_tag('questions')
+  else
+    tagname = self.slug_from_path
+  end
+  Node.where(status: 1, type: 'note')
+      .includes(:revision, :tag)
+      .references(:term_data)
+      .where('term_data.name LIKE ?', "question:#{tagname}")
+end
+
+ +
+ + + + +
+ + +
+ +
+ replace(before, after, user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 801
+def replace(before, after, user)
+  matches = latest.body.scan(before)
+  if matches.length == 1
+    revision = new_revision(uid: user.id,
+                            body: latest.body.gsub(before, after))
+    revision.save
+  else
+    false
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ responded_to(key = 'response') + + click to toggle source + +
+ + +
+ +

Nodes this node is responding to with a `response:<nid>` power tag; +The key word “response” can be customized, i.e. `replication:<nid>` +for other uses.

+ + + + +
+
# File app/models/node.rb, line 291
+def responded_to(key = 'response')
+  Node.where(nid: power_tags(key)) || []
+end
+
+ +
+ + + + +
+ + +
+ +
+ response_count(key = 'response') + + click to toggle source + +
+ + +
+ +

Nodes that respond to this node with a `response:<nid>` power tag; +The key word “response” can be customized, i.e. `replication:<nid>` +for other uses.

+ + + + +
+
# File app/models/node.rb, line 303
+def response_count(key = 'response')
+  Node.where(status: 1, type: 'note')
+      .includes(:revision, :tag)
+      .references(:term_data)
+      .where('term_data.name = ?', "#{key}:#{id}")
+      .count
+end
+
+ +
+ + + + +
+ + +
+ +
+ responses(key = 'response') + + click to toggle source + +
+ + +
+ +

Nodes that respond to this node with a `response:<nid>` power tag; +The key word “response” can be customized, i.e. `replication:<nid>` +for other uses.

+ + + + +
+
# File app/models/node.rb, line 297
+def responses(key = 'response')
+  Tag.find_nodes_by_type([key + ':' + id.to_s])
+end
+
+ +
+ + + + +
+ + +
+ +
+ revision_count() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 197
+def revision_count
+  revision
+    .count
+end
+
+ +
+ + + + +
+ + +
+ +
+ revisions() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 192
+def revisions
+  revision
+    .order('timestamp DESC')
+end
+
+ +
+ + + + +
+ + +
+ +
+ slug_from_path() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 71
+def slug_from_path
+  path.split('/').last
+end
+
+ +
+ + + + +
+ + +
+ +
+ spam() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 158
+def spam
+  self.status = 0
+  save
+  self
+end
+
+ +
+ + + + +
+ + +
+ +
+ subscribers(conditions = false) + + click to toggle source + +
+ + +
+ +

tag- and node-based followers

+ + + + +
+
# File app/models/node.rb, line 221
+def subscribers(conditions = false)
+  users = TagSelection.where(tid: tags.collect(&:tid))
+                      .collect(&:user)
+  users += NodeSelection.where(nid: nid)
+                        .collect(&:user)
+
+  users = users.where(conditions) if conditions
+  users.uniq
+end
+
+ +
+ + + + +
+ + +
+ +
+ tagged_lat() + + click to toggle source + +
+ + +
+ +

these should eventually displace the above means of finding locations …they +may already be redundant after tagged_map_coord migration

+ + + + +
+
# File app/models/node.rb, line 490
+def tagged_lat
+  power_tags('lat')[0]
+end
+
+ +
+ + + + +
+ + +
+ +
+ tagged_lon() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 494
+def tagged_lon
+  power_tags('lon')[0]
+end
+
+ +
+ + + + +
+ + +
+ +
+ tagnames() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 438
+def tagnames
+  tags.collect(&:name)
+end
+
+ +
+ + + + +
+ + +
+ +
+ tagnames_as_classes() + + click to toggle source + +
+ + +
+ +

Here we re-query to fetch /all/ tagnames; this is used in +/views/notes/_notes.html.erb in a way that would otherwise only return a +single tag due to a join, yet select() keeps this efficient

+ + + + +
+
# File app/models/node.rb, line 445
+def tagnames_as_classes
+  Node.select([:nid])
+      .find(id)
+      .tagnames
+      .map { |t| 'tag-' + t.tr(':', '-') }
+      .join(' ')
+end
+
+ +
+ + + + +
+ + +
+ +
+ tags() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 430
+def tags
+  tag
+end
+
+ +
+ + + + +
+ + +
+ +
+ toggle_like(user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 816
+def toggle_like(user)
+  nodes = NodeSelection.where(nid: self.id , liking: true).count
+  if is_liked_by(user)
+    self.cached_likes = nodes-1  
+  else
+    self.cached_likes = nodes+1  
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ totalviews() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 126
+def totalviews
+  # disabled as impressionist is not currently updating counter_cache; see above
+  # self.views + self.legacy_views
+  impressionist_count(filter: :ip_address) + legacy_views
+end
+
+ +
+ + + + +
+ + +
+ +
+ updated_at() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 240
+def updated_at
+  Time.at(self['changed'])
+end
+
+ +
+ + + + +
+ + +
+ +
+ updated_month() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 27
+def updated_month
+  updated_at.strftime('%B %Y')
+end
+
+ +
+ + + + +
+ + +
+ +
+ upgrades() + + click to toggle source + +
+ + +
+ +

so we can quickly fetch upgrades corresponding to this node with +node.upgrades

+ + + + +
+
# File app/models/node.rb, line 761
+def upgrades
+  # override with a tag like `upgrades:h2s`
+  if self.has_power_tag('upgrades')
+    tagname = node.power_tag('upgrades')
+  else
+    tagname = self.slug_from_path
+  end
+  Node.upgrades(tagname)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/NodeSelection.html b/doc/app/NodeSelection.html new file mode 100644 index 0000000000..dd87fb9443 --- /dev/null +++ b/doc/app/NodeSelection.html @@ -0,0 +1,153 @@ + + + + + + +class NodeSelection - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class NodeSelection +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ user() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node_selection.rb, line 8
+def user
+  User.find_by(username: DrupalUser.find_by(uid: user_id).name)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/NodeShared.html b/doc/app/NodeShared.html new file mode 100644 index 0000000000..66fe0ba04c --- /dev/null +++ b/doc/app/NodeShared.html @@ -0,0 +1,747 @@ + + + + + + +module NodeShared - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module NodeShared +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ activities_grid(body) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/node_shared.rb, line 80
+def self.activities_grid(body)
+  body.gsub(/[^\>`](\<p\>)?\[activities\:(\S+)\]/) do |_tagname|
+    tagname = Regexp.last_match(2)
+    nodes = Node.activities(tagname)
+                .order('node.cached_likes DESC')
+    output = ''
+    output += '<p>' if Regexp.last_match(1) == '<p>'
+    a = ActionController::Base.new()
+    output += a.render_to_string(template: "grids/_notes", 
+                                 layout:   false, 
+                                 locals:   {
+                                   tagname: tagname,
+                                   randomSeed: rand(1000).to_s,
+                                   className: 'activity-grid-' + tagname.parameterize,
+                                   nodes: nodes,
+                                   type: "activity"
+                                 })
+    output
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ graph_grid(body, _page = 1) + + click to toggle source + +
+ + +
+ +

rubular regex: rubular.com/r/hBEThNL4qd

+ + + + +
+
# File app/models/concerns/node_shared.rb, line 13
+def self.graph_grid(body, _page = 1)
+  body.gsub(/[^\>`](\<p\>)?\[graph\:(\S+)\]/) do |_tagname|
+    url = Regexp.last_match(2)
+    a = ActionController::Base.new()
+    randomSeed = rand(1000).to_s
+    output = a.render_to_string(template: "grids/_graph", 
+                                layout:   false, 
+                                locals:   {
+                                  url: url,
+                                  randomSeed: randomSeed,
+                                  idName: 'graph-grid-' + randomSeed,
+                                  type: "graph"
+                                })
+    output
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes_grid(body, _page = 1) + + click to toggle source + +
+ + +
+ +

rubular regex: rubular.com/r/hBEThNL4qd

+ + + + +
+
# File app/models/concerns/node_shared.rb, line 31
+def self.notes_grid(body, _page = 1)
+  body.gsub(/[^\>`](\<p\>)?\[notes\:(\S+)\]/) do |_tagname|
+    tagname = Regexp.last_match(2)
+    nodes = Node.where(status: 1, type: 'note')
+                .includes(:revision, :tag)
+                .references(:term_data, :node_revisions)
+                .where('term_data.name = ?', tagname)
+                .order('node_revisions.timestamp DESC')
+    output = ''
+    output += '<p>' if Regexp.last_match(1) == '<p>'
+    a = ActionController::Base.new()
+    output += a.render_to_string(template: "grids/_notes", 
+                                 layout:   false, 
+                                 locals:   {
+                                   tagname: tagname,
+                                   randomSeed: rand(1000).to_s,
+                                   className: 'notes-grid-' + tagname.parameterize,
+                                   nodes: nodes,
+                                   type: "notes"
+                                 })
+    output
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes_map(body) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/node_shared.rb, line 122
+def self.notes_map(body)
+  body.gsub(/[^\>`](\<p\>)?\[map\:content\:(\S+)\:(\S+)\]/) do |_tagname|
+    lat = Regexp.last_match(2)
+    lon = Regexp.last_match(3)
+    nids = NodeTag.joins(:tag)
+                                 .where('name LIKE ?', 'lat:' + lat[0..lat.length - 2] + '%')
+                                 .collect(&:nid)
+    nids = nids || []
+    items = Node.includes(:tag)
+                .references(:node, :term_data)
+                .where('node.nid IN (?) AND term_data.name LIKE ?', nids, 'lon:' + lon[0..lon.length - 2] + '%')
+                .limit(200)
+                .order('node.nid DESC')
+    a = ActionController::Base.new()
+    output = a.render_to_string(template: "map/_leaflet", 
+                                layout:   false, 
+                                locals:   {
+                                  lat:   lat,
+                                  lon:   lon,
+                                  items: items
+                                }
+             )
+    output
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes_map_by_tag(body) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/node_shared.rb, line 148
+def self.notes_map_by_tag(body)
+  body.gsub(/[^\>`](\<p\>)?\[map\:tag\:(\S+)\:(\S+)\:(\S+)\]/) do |_tagname|
+    tagname = Regexp.last_match(2)
+    lat = Regexp.last_match(3)
+    lon = Regexp.last_match(4)
+    nids = NodeTag.joins(:tag)
+                                 .where('term_data.name = ?', tagname)
+                                 .collect(&:nid)
+    nids = NodeTag.joins(:tag)
+                                 .where(nid: nids)
+                                 .where('name LIKE ?', 'lat:' + lat[0..lat.length - 2] + '%')
+                                 .collect(&:nid)
+    nids = nids || []
+    items = Node.includes(:tag)
+                .references(:node, :term_data)
+                .where('node.nid IN (?) AND term_data.name LIKE ?', nids, 'lon:' + lon[0..lon.length - 2] + '%')
+                .limit(200)
+                .order('node.nid DESC')
+    a = ActionController::Base.new()
+    output = a.render_to_string(template: "map/_leaflet", 
+                                layout:   false, 
+                                locals:   {
+                                  lat:   lat,
+                                  lon:   lon,
+                                  items: items
+                                }
+             )
+    output
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ people_grid(body, _page = 1) + + click to toggle source + +
+ + +
+ +

in our interface, “users” are known as “people” because it's more human

+ + + + +
+
# File app/models/concerns/node_shared.rb, line 206
+def self.people_grid(body, _page = 1)
+  body.gsub(/[^\>`](\<p\>)?\[people\:(\S+)\]/) do |_tagname|
+    tagname = Regexp.last_match(2)
+    users = User.where(status: 1)
+                .includes(:user_tags)
+                .references(:user_tags)
+                .where('user_tags.value = ?', tagname)
+    output = ''
+    output += '<p>' if Regexp.last_match(1) == '<p>'
+    a = ActionController::Base.new()
+    output += a.render_to_string(template: "grids/_people", 
+                                 layout:   false, 
+                                 locals:   {
+                                   tagname: tagname,
+                                   randomSeed: rand(1000).to_s,
+                                   className: 'people-grid-' + tagname.parameterize,
+                                   users: users
+                                 })
+    output
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ people_map(body, _page = 1) + + click to toggle source + +
+ + +
+ +

in our interface, “users” are known as “people” because it's more human

+ + + + +
+
# File app/models/concerns/node_shared.rb, line 180
+def self.people_map(body, _page = 1)
+  body.gsub(/[^\>`](\<p\>)?\[map\:people\:(\S+)\:(\S+)\]/) do |_tagname|
+    tagname = Regexp.last_match(2)
+    lat = Regexp.last_match(2)
+    lon = Regexp.last_match(3)
+    nids = nids || []
+    users = User.where(status: 1)
+                .includes(:user_tags)
+                .references(:user_tags)
+                .where('user_tags.value LIKE ?', 'lat:' + lat[0..lat.length - 2] + '%')
+    a = ActionController::Base.new()
+    output = a.render_to_string(template: "map/_leaflet", 
+                                layout:   false, 
+                                locals:   {
+                                  lat:   lat,
+                                  lon:   lon,
+                                  items: users,
+                                  people: true
+                                }
+             )
+    output
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ questions_grid(body, _page = 1) + + click to toggle source + +
+ + +
+ +

rubular regex: rubular.com/r/hBEThNL4qd

+ + + + +
+
# File app/models/concerns/node_shared.rb, line 56
+def self.questions_grid(body, _page = 1)
+  body.gsub(/[^\>`](\<p\>)?\[questions\:(\S+)\]/) do |_tagname|
+    tagname = Regexp.last_match(2)
+    nodes = Node.where(status: 1, type: 'note')
+                .includes(:revision, :tag)
+                .references(:node_revisions, :term_data)
+                .where('term_data.name = ?', "question:#{tagname}")
+                .order('node_revisions.timestamp DESC')
+    output = ''
+    output += '<p>' if Regexp.last_match(1) == '<p>'
+    a = ActionController::Base.new()
+    output += a.render_to_string(template: "grids/_notes", 
+                                 layout:   false, 
+                                 locals:   {
+                                   tagname: tagname,
+                                   randomSeed: rand(1000).to_s,
+                                   className: 'questions-grid-' + tagname.parameterize,
+                                   nodes: nodes,
+                                   type: "questions"
+                                 })
+    output
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ upgrades_grid(body) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/node_shared.rb, line 101
+def self.upgrades_grid(body)
+  body.gsub(/[^\>`](\<p\>)?\[upgrades\:(\S+)\]/) do |_tagname|
+    tagname = Regexp.last_match(2)
+    nodes = Node.upgrades(tagname)
+                .order('node.cached_likes DESC')
+    output = ''
+    output += '<p>' if Regexp.last_match(1) == '<p>'
+    a = ActionController::Base.new()
+    output += a.render_to_string(template: "grids/_notes", 
+                                 layout:   false, 
+                                 locals:   {
+                                   tagname: tagname,
+                                   randomSeed: rand(1000).to_s,
+                                   className: 'upgrades-grid-' + tagname.parameterize,
+                                   nodes: nodes,
+                                   type: "upgrades"
+                                 })
+    output
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ wikis_grid(body, _page = 1) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/node_shared.rb, line 228
+def self.wikis_grid(body, _page = 1)
+   body.gsub(/[^\>`](\<p\>)?\[wikis\:(\S+)\]/) do |_tagname|
+     tagname = Regexp.last_match(2)
+     nodes = Node.where(status: 1, type: 'page')
+                 .includes(:revision, :tag)
+                 .references(:term_data, :node_revisions)
+                 .where('term_data.name = ?', tagname)
+                 .order('node_revisions.timestamp DESC')
+     output = ''
+     output += '<p>' if Regexp.last_match(1) == '<p>'
+     a = ActionController::Base.new()
+     output += a.render_to_string(template: "grids/_wikis", 
+                                  layout:   false, 
+                                  locals:   {
+                                    tagname: tagname,
+                                    randomSeed: rand(1000).to_s,
+                                    className: 'wikis-grid-' + tagname.parameterize,
+                                    nodes: nodes,
+                                    type: "wikis"
+                                  })
+     output
+   end
+ end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ liked_by(uid) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/node_shared.rb, line 8
+def liked_by(uid)
+  likers.collect(&:uid).include?(uid)
+end
+
+ +
+ + + + +
+ + +
+ +
+ likes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/concerns/node_shared.rb, line 4
+def likes
+  cached_likes
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/NodeTag.html b/doc/app/NodeTag.html new file mode 100644 index 0000000000..7bee32d3e1 --- /dev/null +++ b/doc/app/NodeTag.html @@ -0,0 +1,331 @@ + + + + + + +class NodeTag - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class NodeTag +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ author() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node_tag.rb, line 19
+def author
+  user
+end
+
+ +
+ + + + +
+ + +
+ +
+ description() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node_tag.rb, line 35
+def description
+  self.tag.description if self.tag && self.tag.description && !self.tag.description.empty?
+end
+
+ +
+ + + + +
+ + +
+ +
+ drupal_user() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node_tag.rb, line 27
+def drupal_user
+  DrupalUser.find uid
+end
+
+ +
+ + + + +
+ + +
+ +
+ increment_count() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node_tag.rb, line 12
+def increment_count
+  tag = self.tag
+  tag.count = 0 if tag.count.nil?
+  tag.count += 1
+  tag.save
+end
+
+ +
+ + + + +
+ + +
+ +
+ name() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node_tag.rb, line 31
+def name
+  tag.name
+end
+
+ +
+ + + + +
+ + +
+ +
+ user() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node_tag.rb, line 23
+def user
+  DrupalUser.find_by(uid: uid).try(:user)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/NotesController.html b/doc/app/NotesController.html new file mode 100644 index 0000000000..881d733f5e --- /dev/null +++ b/doc/app/NotesController.html @@ -0,0 +1,1000 @@ + + + + + + +class NotesController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class NotesController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ author() + + click to toggle source + +
+ + +
+ +

notes for a given author

+ + + + +
+
# File app/controllers/notes_controller.rb, line 255
+def author
+  @user = DrupalUser.find_by(name: params[:id])
+  @title = @user.name
+  @notes = Node.page(params[:page])
+               .order('nid DESC')
+               .where(type: 'note', status: 1, uid: @user.uid)
+  render template: 'notes/index'
+end
+
+ +
+ + + + +
+ + +
+ +
+ author_topic() + + click to toggle source + +
+ + +
+ +

notes for given comma-delimited tags params for author

+ + + + +
+
# File app/controllers/notes_controller.rb, line 265
+def author_topic
+  @user = DrupalUser.find_by(name: params[:author])
+  @tagnames = params[:topic].split('+')
+  @title = @user.name + " on '" + @tagnames.join(', ') + "'"
+  @notes = @user.notes_for_tags(@tagnames)
+  @unpaginated = true
+  render template: 'notes/index'
+end
+
+ +
+ + + + +
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 92
+def create
+  if current_user.drupal_user.status == 1
+    saved, @node, @revision = Node.new_note(uid: current_user.uid,
+                                            title: params[:title],
+                                            body: params[:body],
+                                            main_image: params[:main_image])
+
+    if saved
+      if params[:tags]
+        params[:tags].tr(' ', ',').split(',').each do |tagname|
+          @node.add_tag(tagname.strip, current_user)
+        end
+      end
+      if params[:event] == 'on'
+        @node.add_tag('event', current_user)
+        @node.add_tag('event:rsvp', current_user)
+        @node.add_tag('date:' + params[:date], current_user) if params[:date]
+      end
+      if current_user.first_time_poster
+        AdminMailer.notify_node_moderators(@node)
+        flash[:first_time_post] = true
+        if @node.has_power_tag('question')
+          flash[:notice] = I18n.t('notes_controller.thank_you_for_question').html_safe
+        else
+          flash[:notice] = I18n.t('notes_controller.thank_you_for_contribution').html_safe
+        end
+      else
+        if @node.has_power_tag('question')
+          flash[:notice] = I18n.t('notes_controller.question_note_published').html_safe
+        else
+          flash[:notice] = I18n.t('notes_controller.research_note_published').html_safe
+        end
+      end
+      # Notice: Temporary redirect.Remove this condition after questions show page is complete.
+      #         Just keep @node.path(:question)
+      if params[:redirect] && params[:redirect] == 'question'
+        redirect_to @node.path(:question)
+      else
+        if request.xhr? # rich editor!
+          render text: @node.path
+        else
+          redirect_to @node.path
+        end
+      end
+    else
+      if request.xhr? # rich editor!
+        errors = @node.errors
+        errors = errors.to_hash.merge(@revision.errors.to_hash) if @revision && @revision.errors
+        render json: errors
+      else
+        render template: 'editor/post'
+      end
+    end
+  else
+    flash.keep[:error] = I18n.t('notes_controller.you_have_been_banned').html_safe
+    redirect_to '/logout'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ +

at /notes/delete/:id only for notes

+ + + + +
+
# File app/controllers/notes_controller.rb, line 235
+def delete
+  @node = Node.find(params[:id])
+  if current_user.uid == @node.uid && @node.type == 'note' || current_user.role == 'admin' || current_user.role == 'moderator'
+    @node.delete
+    respond_with do |format|
+      format.html do
+        if request.xhr?
+          render text: I18n.t('notes_controller.content_deleted')
+        else
+          flash[:notice] = I18n.t('notes_controller.content_deleted')
+          redirect_to '/dashboard' + '?_=' + Time.now.to_i.to_s
+        end
+      end
+    end
+  else
+    prompt_login
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ edit() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 151
+def edit
+  @node = Node.find_by(nid: params[:id], type: 'note')
+  if current_user.uid == @node.uid || current_user.role == 'admin' || @node.has_tag("with:#{current_user.username}")
+    if params[:legacy]
+      render template: 'editor/post'
+    else
+      if @node.main_image
+        @main_image = @node.main_image.path(:default)
+      elsif params[:main_image] && Image.find_by(id: params[:main_image])
+        @main_image = Image.find_by(id: params[:main_image]).path
+      elsif @image
+        @main_image = @image.path(:default)
+      end
+      flash.now[:notice] = "This is the new rich editor. For the legacy editor, <a href='/notes/edit/#{@node.id}?#{request.env['QUERY_STRING']}&legacy=true'>click here</a>."
+      render template: 'editor/rich'
+    end
+  else
+    if @node.has_power_tag('question')
+      prompt_login I18n.t('notes_controller.author_can_edit_question')
+    else
+      prompt_login I18n.t('notes_controller.author_can_edit_note')
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ image() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 82
+def image
+  params[:size] = params[:size] || :large
+  node = Node.find(params[:id])
+  if node.main_image
+    redirect_to node.main_image.path(params[:size])
+  else
+    redirect_to 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 5
+def index
+  @title = I18n.t('notes_controller.research_notes')
+  set_sidebar
+end
+
+ +
+ + + + +
+ + +
+ +
+ liked() + + click to toggle source + +
+ + +
+ +

notes with high # of likes

+ + + + +
+
# File app/controllers/notes_controller.rb, line 275
+def liked
+  @title = I18n.t('notes_controller.highly_liked_research_notes')
+  @wikis = Node.limit(10)
+               .where(type: 'page', status: 1)
+               .order('nid DESC')
+
+  @notes = Node.research_notes
+               .where(status: 1)
+               .limit(20)
+               .order('nid DESC')
+  @unpaginated = true
+  render template: 'notes/index'
+end
+
+ +
+ + + + +
+ + +
+ +
+ liked_rss() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 316
+def liked_rss
+  @notes = Node.limit(20)
+               .order('created DESC')
+               .where('type = ? AND status = 1 AND cached_likes > 0', 'note')
+  respond_to do |format|
+    format.rss do
+      render layout: false, template: 'notes/rss'
+      response.headers['Content-Type'] = 'application/xml; charset=utf-8'
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ places() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 14
+def places
+  @title = 'Places'
+  @notes = Node.joins('LEFT OUTER JOIN node_revisions ON node_revisions.nid = node.nid 
+                       LEFT OUTER JOIN community_tags ON community_tags.nid = node.nid 
+                       LEFT OUTER JOIN term_data ON term_data.tid = community_tags.tid')
+               .select('*, max(node_revisions.timestamp)')
+               .where(status: 1, type:%w[page place])
+               .includes(:revision, :tag)
+               .references(:term_data)
+               .where('term_data.name = ?', 'chapter')
+               .group('node.nid')
+               .order('max(node_revisions.timestamp) DESC, node.nid')
+               .page(params[:page])
+
+  render template: 'notes/tools_places'
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+ raw() + + click to toggle source + +
+ + +
+ +

display a revision, raw

+ + + + +
+
# File app/controllers/notes_controller.rb, line 41
+def raw
+  response.headers['Content-Type'] = 'text/plain; charset=utf-8'
+  render text: Node.find(params[:id]).latest.body
+end
+
+ +
+ + + + +
+ + +
+ +
+ rss() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 303
+def rss
+  @notes = Node.limit(20)
+               .order('nid DESC')
+               .where('type = ? AND status = 1 AND created < ?', 'note', (Time.now.to_i - 30.minutes.to_i))
+  respond_to do |format|
+    format.rss do
+      render layout: false
+      response.headers['Content-Type'] = 'application/xml; charset=utf-8'
+      response.headers['Access-Control-Allow-Origin'] = '*'
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ rsvp() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 328
+def rsvp
+  @node = Node.find params[:id]
+  # leave a comment
+  @comment = @node.add_comment(subject: 'rsvp', uid: current_user.uid, body: 'I will be attending!')
+  # make a tag
+  @node.add_tag('rsvp:' + current_user.username, current_user)
+  redirect_to @node.path + '#comments'
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+ show() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 46
+def show
+  if params[:author] && params[:date]
+    @node = Node.find_notes(params[:author], params[:date], params[:id])
+    @node ||= Node.where(path: "/report/#{params[:id]}").first
+    # redirect_old_urls
+  else
+    @node = Node.find params[:id]
+  end
+
+  if @node.has_power_tag('question')
+    redirect_to @node.path(:question)
+    return
+  end
+
+  if @node.has_power_tag('redirect')
+    if current_user.nil? || (current_user.role != 'admin' && current_user.role != 'moderator')
+      redirect_to Node.find(@node.power_tag('redirect')).path
+      return
+    elsif current_user.role == 'admin' || current_user.role == 'moderator'
+      flash.now[:warning] = "Only moderators and admins see this page, as it is redirected to #{Node.find(@node.power_tag('redirect')).title}.
+      To remove the redirect, delete the tag beginning with 'redirect:'"
+    end
+  end
+
+  return if check_and_redirect_node(@node)
+
+  alert_and_redirect_moderated
+
+  impressionist(@node, 'show', unique: [:ip_address])
+  @title = @node.latest.title
+  @tags = @node.tags
+  @tagnames = @tags.collect(&:name)
+
+  set_sidebar :tags, @tagnames
+end
+
+ +
+ + + + +
+ + +
+ +
+ tools() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/notes_controller.rb, line 10
+def tools
+  redirect_to '/methods', status: 302
+end
+
+ +
+ + + + +
+ + +
+ +
+ update() + + click to toggle source + +
+ + +
+ +

at /notes/update/:id

+ + + + +
+
# File app/controllers/notes_controller.rb, line 177
+def update
+  @node = Node.find(params[:id])
+  if current_user.uid == @node.uid || current_user.role == 'admin' || @node.has_tag("with:#{current_user.username}")
+    @revision = @node.latest
+    @revision.title = params[:title]
+    @revision.body = params[:body]
+    if params[:tags]
+      params[:tags].tr(' ', ',').split(',').each do |tagname|
+        @node.add_tag(tagname, current_user)
+      end
+    end
+    if @revision.valid?
+      @revision.save
+      @node.vid = @revision.vid
+      # update vid (version id) of main image
+      if @node.drupal_main_image
+        i = @node.drupal_main_image
+        i.vid = @revision.vid
+        i.save
+      end
+      @node.drupal_content_field_image_gallery.each do |img|
+        img.vid = @revision.vid
+        img.save
+      end
+      @node.title = @revision.title
+      # save main image
+      if params[:main_image] && params[:main_image] != ''
+        img = Image.find params[:main_image]
+        unless img.nil?
+          img.nid = @node.id
+          @node.main_image_id = img.id
+          img.save
+        end
+      end
+      @node.save!
+      flash[:notice] = I18n.t('notes_controller.edits_saved')
+      format = false
+      format = :question if params[:redirect] && params[:redirect] == 'question'
+      if request.xhr?
+        render text: @node.path(format) + '?_=' + Time.now.to_i.to_s
+      else
+        redirect_to @node.path(format) + '?_=' + Time.now.to_i.to_s
+      end
+    else
+      flash[:error] = I18n.t('notes_controller.edit_not_saved')
+      if request.xhr? || params[:rich]
+        errors = @node.errors
+        errors = errors.to_hash.merge(@revision.errors.to_hash) if @revision && @revision.errors
+        render json: errors
+      else
+        render 'editor/post'
+     end
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/NotesHelper.html b/doc/app/NotesHelper.html new file mode 100644 index 0000000000..bf7b6576ec --- /dev/null +++ b/doc/app/NotesHelper.html @@ -0,0 +1,95 @@ + + + + + + +module NotesHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module NotesHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Object.html b/doc/app/Object.html new file mode 100644 index 0000000000..f9fa405d9a --- /dev/null +++ b/doc/app/Object.html @@ -0,0 +1,113 @@ + + + + + + +class Object - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Object +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/OpenIdAuthentication.html b/doc/app/OpenIdAuthentication.html new file mode 100644 index 0000000000..1fb6a0f62a --- /dev/null +++ b/doc/app/OpenIdAuthentication.html @@ -0,0 +1,323 @@ + + + + + + +module OpenIdAuthentication - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module OpenIdAuthentication +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ new(app) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 6
+def self.new(app)
+  store = OpenIdAuthentication.store
+  if store.nil?
+    Rails.logger.warn "OpenIdAuthentication.store is nil. Using in-memory store."
+  end
+
+  ::Rack::OpenID.new(app, OpenIdAuthentication.store)
+end
+
+ +
+ + + + +
+ + +
+ +
+ store() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 15
+def self.store
+  @@store
+end
+
+ +
+ + + + +
+ + +
+ +
+ store=(*store_option) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 19
+def self.store=(*store_option)
+  store, *parameters = *([ store_option ].flatten)
+
+  @@store = case store
+  when :memory
+    require 'openid/store/memory'
+    OpenID::Store::Memory.new
+  when :file
+    require 'openid/store/filesystem'
+    OpenID::Store::Filesystem.new(Rails.root.join('tmp/openids'))
+  when :memcache
+    require 'memcache'
+    require 'openid/store/memcache'
+    OpenID::Store::Memcache.new(MemCache.new(parameters))
+  else
+    store
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Protected Instance Methods

+
+ + +
+ +
+ authenticate_with_open_id(identifier = nil, options = {}, &block) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 86
+def authenticate_with_open_id(identifier = nil, options = {}, &block) #:doc:
+  identifier ||= open_id_identifier
+
+  if request.env[Rack::OpenID::RESPONSE]
+    complete_open_id_authentication(&block)
+  else
+    begin_open_id_authentication(identifier, options, &block)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ using_open_id?(identifier = nil) + + click to toggle source + +
+ + +
+ +

The parameter name of “openid_identifier” is used rather than the Rails +convention “open_id_identifier” because that's what the specification +dictates in order to get browser auto-complete working across sites

+ + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 81
+def using_open_id?(identifier = nil) #:doc:
+  identifier ||= open_id_identifier
+  !identifier.blank? || request.env[Rack::OpenID::RESPONSE]
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/OpenIdAuthentication/Result.html b/doc/app/OpenIdAuthentication/Result.html new file mode 100644 index 0000000000..809ae1ab3b --- /dev/null +++ b/doc/app/OpenIdAuthentication/Result.html @@ -0,0 +1,350 @@ + + + + + + +class OpenIdAuthentication::Result - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class OpenIdAuthentication::Result +

+ +
+ +
+ + + + +
+ + + + + +
+
+

Constants

+
+
+ +
ERROR_MESSAGES + +
+ + +
+
+ + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ [](code) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 49
+def self.[](code)
+  new(code)
+end
+
+ +
+ + + + +
+ + +
+ +
+ new(code) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 53
+def initialize(code)
+  @code = code
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ message() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 71
+def message
+  ERROR_MESSAGES[@code]
+end
+
+ +
+ + + + +
+ + +
+ +
+ status() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 57
+def status
+  @code
+end
+
+ +
+ + + + +
+ + +
+ +
+ successful?() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 63
+def successful?
+  @code == :successful
+end
+
+ +
+ + + + +
+ + +
+ +
+ unsuccessful?() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/open_id_authentication/open_id_authentication.rb, line 67
+def unsuccessful?
+  ERROR_MESSAGES.keys.include?(@code)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/OpenidController.html b/doc/app/OpenidController.html new file mode 100644 index 0000000000..9dd5c0009b --- /dev/null +++ b/doc/app/OpenidController.html @@ -0,0 +1,852 @@ + + + + + + +class OpenidController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class OpenidController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ decision() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 172
+def decision
+  oidreq = session[:last_oidreq]
+  session[:last_oidreq] = nil
+
+  if params[:yes].nil?
+    redirect_to oidreq.cancel_url
+    return
+  else
+    id_to_send = params[:id_to_send]
+
+    identity = oidreq.identity
+    if oidreq.id_select
+      if id_to_send && (id_to_send != '')
+        session[:username] = id_to_send
+        session[:approvals] = []
+        identity = url_for_user
+      else
+        msg = 'You must enter a username to in order to send '                  'an identifier to the Relying Party.'
+        show_decision_page(oidreq, msg)
+        return
+      end
+    else
+      session[:username] = current_user.username
+    end
+
+    if session[:approvals]
+      session[:approvals] << oidreq.trust_root
+    else
+      session[:approvals] = [oidreq.trust_root]
+    end
+    oidresp = oidreq.answer(true, nil, identity)
+    add_sreg(oidreq, oidresp)
+    add_pape(oidreq, oidresp)
+    return render_response(oidresp)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ idp_xrds() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 164
+def idp_xrds
+  types = [
+    OpenID::OPENID_IDP_2_0_TYPE
+  ]
+
+  render_xrds(types)
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 16
+def index
+  begin
+    if params['openid.mode']
+      oidreq = server.decode_request(params)
+    else
+      oidreq = server.decode_request(Rack::Utils.parse_query(request.env['ORIGINAL_FULLPATH'].split('?')[1]))
+    end
+  rescue ProtocolError => e
+    # invalid openid request, so just display a page with an error message
+    render text: e.to_s, status: 500
+    return
+  end
+
+  # no openid.mode was given
+  unless oidreq
+    render text: 'This is an OpenID server endpoint.'
+    return
+  end
+
+  if current_user.nil? && !params['openid.mode']
+    session[:openid_return_to] = request.env['ORIGINAL_FULLPATH']
+    flash[:warning] = 'Please log in first.'
+    redirect_to '/login'
+    return
+  else
+
+    if oidreq
+
+      requested_username = ''
+      if request.env['ORIGINAL_FULLPATH'] && request.env['ORIGINAL_FULLPATH'].split('?')[1]
+        request.env['ORIGINAL_FULLPATH'].split('?')[1].split('&').each do |param|
+          requested_username = param.split('=')[1].split('%2F').last if param.split('=')[0] == 'openid.claimed_id'
+        end
+      end
+
+      if current_user && !requested_username.casecmp(current_user.username.downcase).zero?
+        flash[:error] = "You are requesting access to an account that's not yours. Please <a href='/logout'>log out</a> and use the correct account, or <a href='" + oidreq.trust_root + "'>try to login with the correct username</a>"
+        redirect_to '/dashboard'
+      else
+        oidresp = nil
+
+        if oidreq.is_a?(CheckIDRequest)
+
+          identity = oidreq.identity
+
+          if oidreq.id_select
+            if oidreq.immediate
+              oidresp = oidreq.answer(false)
+            elsif session[:username]
+              # The user hasn't logged in.
+              # show_decision_page(oidreq) # this doesnt make sense... it was in the example though
+              session[:openid_return_to] = request.env['ORIGINAL_FULLPATH']
+              redirect_to '/login'
+            else
+              # Else, set the identity to the one the user is using.
+              identity = url_for_user
+            end
+
+          end
+
+          if oidresp
+            nil
+          elsif is_authorized(identity, oidreq.trust_root)
+            oidresp = oidreq.answer(true, nil, identity)
+
+            # add the sreg response if requested
+            add_sreg(oidreq, oidresp)
+            # ditto pape
+            add_pape(oidreq, oidresp)
+
+          elsif oidreq.immediate
+            server_url = url_for action: 'index'
+            oidresp = oidreq.answer(false, server_url)
+
+          else
+            show_decision_page(oidreq)
+            return
+          end
+
+        else
+          oidresp = server.handle_request(oidreq)
+        end
+
+        render_response(oidresp)
+      end
+    else
+      session[:openid_return_to] = request.env['ORIGINAL_FULLPATH']
+      redirect_to '/login'
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ resume() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 108
+def resume
+  if session[:openid_return_to] # for openid login, redirects back to openid auth process
+    return_to = session[:openid_return_to]
+    session[:openid_return_to] = nil
+    session[:openid_requester] = nil
+    redirect_to return_to
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ show_decision_page(oidreq, message = 'Do you trust this site with your identity?') + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 117
+def show_decision_page(oidreq, message = 'Do you trust this site with your identity?')
+  session[:last_oidreq] = oidreq
+  @oidreq = oidreq
+
+  flash[:notice] = message if message
+
+  render template: 'openid/decide'
+end
+
+ +
+ + + + +
+ + +
+ +
+ user_page() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 126
+  def user_page
+    # Yadis content-negotiation: we want to return the xrds if asked for.
+    accept = request.env['HTTP_ACCEPT']
+
+    # This is not technically correct, and should eventually be updated
+    # to do real Accept header parsing and logic.  Though I expect it will work
+    # 99% of the time.
+    if accept && accept.include?('application/xrds+xml')
+      user_xrds
+      return
+    end
+
+    # content negotiation failed, so just render the user page
+    xrds_url = url_for(controller: 'user', action: params[:username]) + '/xrds'
+    identity_page = <<EOS
+<html><head>
+<meta http-equiv="X-XRDS-Location" content="#{xrds_url}" />
+<link rel="openid.server" href="#{url_for action: 'index'}" />
+</head><body><p>OpenID identity page for #{params[:username]}</p>
+</body></html>
+EOS
+
+    # Also add the Yadis location header, so that they don't have
+    # to parse the html unless absolutely necessary.
+    response.headers['X-XRDS-Location'] = xrds_url
+    render text: identity_page
+  end
+
+ +
+ + + + +
+ + +
+ +
+ user_xrds() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 154
+def user_xrds
+  types = [
+    OpenID::OPENID_2_0_TYPE,
+    OpenID::OPENID_1_0_TYPE,
+    OpenID::SREG_URI
+  ]
+
+  render_xrds(types)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Protected Instance Methods

+
+ + +
+ +
+ add_pape(oidreq, oidresp) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 273
+def add_pape(oidreq, oidresp)
+  papereq = OpenID::PAPE::Request.from_openid_request(oidreq)
+  return if papereq.nil?
+  paperesp = OpenID::PAPE::Response.new
+  paperesp.nist_auth_level = 0 # we don't even do auth at all!
+  oidresp.add_extension(paperesp)
+end
+
+ +
+ + + + +
+ + +
+ +
+ add_sreg(oidreq, oidresp) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 256
+def add_sreg(oidreq, oidresp)
+  # check for Simple Registration arguments and respond
+  sregreq = OpenID::SReg::Request.from_openid_request(oidreq)
+
+  return if sregreq.nil?
+  # In a real application, this data would be user-specific,
+  # and the user should be asked for permission to release
+  # it.
+  sreg_data = {
+    'nickname' => current_user.username, # session[:username],
+    'email' => current_user.email
+  }
+
+  sregresp = OpenID::SReg::Response.extract_response(sregreq, sreg_data)
+  oidresp.add_extension(sregresp)
+end
+
+ +
+ + + + +
+ + +
+ +
+ approved(trust_root) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 222
+def approved(trust_root)
+  return false if session[:approvals].nil?
+  session[:approvals].member?(trust_root)
+end
+
+ +
+ + + + +
+ + +
+ +
+ is_authorized(identity_url, trust_root) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 227
+def is_authorized(identity_url, trust_root)
+  (session[:username] && (identity_url == url_for_user) && approved(trust_root))
+end
+
+ +
+ + + + +
+ + +
+ +
+ render_response(oidresp) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 281
+def render_response(oidresp)
+  signed_response = server.signatory.sign(oidresp) if oidresp.needs_signing
+  web_response = server.encode_response(oidresp)
+  case web_response.code
+  when HTTP_OK
+    render text: web_response.body, status: 200
+
+  when HTTP_REDIRECT
+    redirect_to web_response.headers['location']
+
+  else
+    render text: web_response.body, status: 400
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ render_xrds(types) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 231
+  def render_xrds(types)
+    type_str = ''
+
+    types.each do |uri|
+      type_str += "<Type>#{uri}</Type>\n      "
+    end
+
+    yadis = <<EOS
+<?xml version="1.0" encoding="UTF-8"?>
+<xrds:XRDS
+    xmlns:xrds="xri://$xrds"
+    xmlns="xri://$xrd*($v*2.0)">
+  <XRD>
+    <Service priority="0">
+      #{type_str}
+      <URI>#{url_for(controller: 'openid', only_path: false)}</URI>
+    </Service>
+  </XRD>
+</xrds:XRDS>
+EOS
+
+    response.headers['content-type'] = 'application/xrds+xml'
+    render text: yadis
+  end
+
+ +
+ + + + +
+ + +
+ +
+ server() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/openid_controller.rb, line 212
+def server
+  if @server.nil?
+    server_url = url_for action: 'index', only_path: false
+    dir = Pathname.new(request.host).join('db').join('openid-store')
+    store = OpenID::Store::Filesystem.new(dir)
+    @server = Server.new(store, server_url)
+  end
+  @server
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/OpenidHelper.html b/doc/app/OpenidHelper.html new file mode 100644 index 0000000000..0c72ef5dec --- /dev/null +++ b/doc/app/OpenidHelper.html @@ -0,0 +1,146 @@ + + + + + + +module OpenidHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module OpenidHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ url_for_user() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/helpers/openid_helper.rb, line 3
+def url_for_user
+  '/profile/' + current_user.username
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/PasswordResetMailer.html b/doc/app/PasswordResetMailer.html new file mode 100644 index 0000000000..b54b3db0b0 --- /dev/null +++ b/doc/app/PasswordResetMailer.html @@ -0,0 +1,169 @@ + + + + + + +class PasswordResetMailer - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class PasswordResetMailer +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ reset_notify(user, key) + + click to toggle source + +
+ + +
+ +

#reset_notify.deliver

+ + + + +
+
# File app/mailers/password_reset_mailer.rb, line 7
+def reset_notify(user, key)
+  subject = '[Public Lab] Reset your password'
+  @user = user
+  @key = key
+  @footer = feature('email-footer')
+  mail(to: user.email, subject: subject).deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/QuestionsController.html b/doc/app/QuestionsController.html new file mode 100644 index 0000000000..9c7d7c7a50 --- /dev/null +++ b/doc/app/QuestionsController.html @@ -0,0 +1,477 @@ + + + + + + +class QuestionsController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class QuestionsController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ answered() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/questions_controller.rb, line 66
+def answered
+  @title = 'Recently answered'
+  @questions = Node.questions
+                   .where(status: 1)
+  @questions = filter_questions_by_tag(@questions, params[:tagnames])
+               .joins(:answers)
+               .order('answers.created_at DESC')
+               .group('node.nid')
+               .paginate(page: params[:page], per_page: 24)
+  @wikis = Node.limit(10)
+               .where(type: 'page', status: 1)
+               .order('nid DESC')
+  render template: 'questions/index'
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/questions_controller.rb, line 21
+def index
+  @title = 'Questions and Answers'
+  set_sidebar
+  @questions = Node.questions
+                   .where(status: 1)
+                   .order('node.nid DESC')
+                   .paginate(page: params[:page], per_page: 24)
+end
+
+ +
+ + + + +
+ + +
+ +
+ liked() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/questions_controller.rb, line 118
+def liked
+  @title = 'Highly liked Questions'
+  @questions = Node.questions.where(status: 1)
+  @questions = filter_questions_by_tag(@questions, params[:tagnames])
+               .order('cached_likes DESC')
+               .limit(20)
+
+  @wikis = Node.limit(10)
+               .where(type: 'page', status: 1)
+               .order('nid DESC')
+  @unpaginated = true
+  render template: 'questions/index'
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/questions_controller.rb, line 30
+def new
+  if current_user == nil
+    redirect_to new_user_session_path( return_to: request.path )
+    flash[:notice] = "Your question is important and we want to hear from you! Please log in or sign up to post a question"
+  else
+    if params[:legacy]
+      render 'editor/question'
+    else
+      render 'editor/questionRich'
+    end
+  end
+end
+
+ +
+ + + + +
+ + + + + + + + +
+ +
+ show() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/questions_controller.rb, line 43
+def show
+  if params[:author] && params[:date]
+    @node = Node.find_notes(params[:author], params[:date], params[:id])
+    @node ||= Node.where(path: "/report/#{params[:id]}").first
+  else
+    @node = Node.find params[:id]
+  end
+
+  redirect_to @node.path unless @node.has_power_tag('question')
+
+  alert_and_redirect_moderated
+
+  impressionist(@node)
+  @title = @node.latest.title
+  @tags = @node.power_tag_objects('question')
+  @tagnames = @tags.collect(&:name)
+  @users = @node.answers.group(:uid)
+                .order('count(*) DESC')
+                .collect(&:author)
+
+  set_sidebar :tags, @tagnames
+end
+
+ +
+ + + + +
+ + +
+ +
+ unanswered() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/questions_controller.rb, line 81
+def unanswered
+  @title = 'Unanswered questions'
+  @questions = Node.questions
+                   .where(status: 1)
+                   .includes(:answers)
+                   .references(:answers)
+                   .where(answers: { id: nil })
+                   .order('answers.created_at DESC')
+                   .group('node.nid')
+                   .paginate(page: params[:page], per_page: 24)
+  render template: 'questions/index'
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/README_rdoc.html b/doc/app/README_rdoc.html new file mode 100644 index 0000000000..01b81d039d --- /dev/null +++ b/doc/app/README_rdoc.html @@ -0,0 +1,391 @@ + + + + + + +README - Rails Application Documentation + + + + + + + + + + + + + + +
+ +

Welcome to Rails

+ +

Rails is a web-application framework that includes everything needed to +create database-backed web applications according to the Model-View-Control +pattern.

+ +

This pattern splits the view (also called the presentation) into “dumb” +templates that are primarily responsible for inserting pre-built data in +between HTML tags. The model contains the “smart” domain objects (such as +Account, Product, Person, Post) that holds all the business logic and knows +how to persist themselves to a database. The controller handles the +incoming requests (such as Save New Account, Update Product, Show Post) by +manipulating the model and directing data to the view.

+ +

In Rails, the model is handled by what's called an object-relational +mapping layer entitled Active Record. This layer allows you to present the +data from database rows as objects and embellish these data objects with +business logic methods. You can read more about Active Record in files/vendor/rails/activerecord/README.html.

+ +

The controller and view are handled by the Action Pack, which handles both +layers by its two parts: Action View and Action Controller. These two +layers are bundled in a single package due to their heavy interdependence. +This is unlike the relationship between the Active Record and Action Pack +that is much more separate. Each of these packages can be used +independently outside of Rails. You can read more about Action Pack in files/vendor/rails/actionpack/README.html.

+ +

Getting Started

+
  1. +

    At the command prompt, create a new Rails application:

    + +
    <tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name)
    +
  2. +

    Change directory to myapp and start the web server:

    + +
    <tt>cd myapp; rails server</tt> (run with --help for options)
    +
  3. +

    Go to localhost:3000/ and you'll +see:

    + +
    "Welcome aboard: You're riding Ruby on Rails!"
    +
    +
  4. +

    Follow the guidelines to start developing your application. You can find

    +
+ +

the following resources handy:

+ + +

Debugging Rails

+ +

Sometimes your application goes wrong. Fortunately there are a lot of tools +that will help you debug it and get it back on the rails.

+ +

First area to check is the application log files. Have “tail -f” commands +running on the server.log and development.log. Rails will automatically +display debugging and runtime information to these files. Debugging info +will also be shown in the browser on requests from 127.0.0.1.

+ +

You can also log your own messages directly into the log file from your +code using the Ruby logger class from inside your controllers. Example:

+ +
class WeblogController < ActionController::Base
+  def destroy
+    @weblog = Weblog.find(params[:id])
+    @weblog.destroy
+    logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
+  end
+end
+
+ +

The result will be a message in your log file along the lines of:

+ +
Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1!
+ +

More information on how to use the logger is at www.ruby-doc.org/core/

+ +

Also, Ruby documentation can be found at www.ruby-lang.org/. There are several +books available online as well:

+ + +

These two books will bring you up to speed on the Ruby language and also on +programming in general.

+ +

Debugger

+ +

Debugger support is available through the debugger command when you start +your Mongrel or WEBrick server with –debugger. This means that you can +break out of execution at any point in the code, investigate and change the +model, and then, resume execution! You need to install ruby-debug to run +the server in debugging mode. With gems, use sudo gem install +ruby-debug. Example:

+ +
class WeblogController < ActionController::Base
+  def index
+    @posts = Post.all
+    debugger
+  end
+end
+
+ +

So the controller will accept the action, run the first line, then present +you with a IRB prompt in the server window. Here you can do things like:

+ +
>> @posts.inspect
+=> "[#<Post:0x14a6be8
+        @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>,
+     #<Post:0x14a6620
+        @attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]"
+>> @posts.first.title = "hello from a debugger"
+=> "hello from a debugger"
+ +

…and even better, you can examine how your runtime objects actually work:

+ +
>> f = @posts.first
+=> #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
+>> f.
+Display all 152 possibilities? (y or n)
+ +

Finally, when you're ready to resume execution, you can enter “cont”.

+ +

Console

+ +

The console is a Ruby shell, which allows you to interact with your +application's domain model. Here you'll have all parts of the +application configured, just like it is when the application is running. +You can inspect domain models, change values, and save to the database. +Starting the script without arguments will launch it in the development +environment.

+ +

To start the console, run rails console from the application +directory.

+ +

Options:

+ + +

To reload your controllers and models after launching the console run +reload!

+ +

More information about irb can be found at: http://www.rubycentral.org/pickaxe/irb.html

+ +

dbconsole

+ +

You can go to the command line of your database directly through +rails dbconsole. You would be connected to the database with +the credentials defined in database.yml. Starting the script without +arguments will connect you to the development database. Passing an argument +will connect you to a different database, like rails dbconsole +production. Currently works for MySQL, PostgreSQL and SQLite 3.

+ +

Description of Contents

+ +

The default directory structure of a generated Ruby on Rails application:

+ +
|-- app
+|   |-- assets
+|       |-- images
+|       |-- javascripts
+|       `-- stylesheets
+|   |-- controllers
+|   |-- helpers
+|   |-- mailers
+|   |-- models
+|   `-- views
+|       `-- layouts
+|-- config
+|   |-- environments
+|   |-- initializers
+|   `-- locales
+|-- db
+|-- doc
+|-- lib
+|   `-- tasks
+|-- log
+|-- public
+|-- script
+|-- test
+|   |-- fixtures
+|   |-- functional
+|   |-- integration
+|   |-- performance
+|   `-- unit
+|-- tmp
+|   |-- cache
+|   |-- pids
+|   |-- sessions
+|   `-- sockets
+`-- vendor
+    |-- assets
+        `-- stylesheets
+    `-- plugins
+ +

app

+ +
Holds all the code that's specific to this particular application.
+ +

app/assets

+ +
Contains subdirectories for images, stylesheets, and JavaScript files.
+ +

app/controllers

+ +
Holds controllers that should be named like weblogs_controller.rb for
+automated URL mapping. All controllers should descend from
+ApplicationController which itself descends from ActionController::Base.
+ +

app/models

+ +
Holds models that should be named like post.rb. Models descend from
+ActiveRecord::Base by default.
+ +

app/views

+ +
Holds the template files for the view that should be named like
+weblogs/index.html.erb for the WeblogsController#index action. All views use
+eRuby syntax by default.
+ +

app/views/layouts

+ +
Holds the template files for layouts to be used with views. This models the
+common header/footer method of wrapping views. In your views, define a layout
+using the <tt>layout :default</tt> and create a file named default.html.erb.
+Inside default.html.erb, call <% yield %> to render the view using this
+layout.
+ +

app/helpers

+ +
Holds view helpers that should be named like weblogs_helper.rb. These are
+generated for you automatically when using generators for controllers.
+Helpers can be used to wrap functionality for your views into methods.
+ +

config

+ +
Configuration files for the Rails environment, the routing map, the database,
+and other dependencies.
+ +

db

+ +
Contains the database schema in schema.rb. db/migrate contains all the
+sequence of Migrations for your schema.
+ +

doc

+ +
This directory is where your application documentation will be stored when
+generated using <tt>rake doc:app</tt>
+ +

lib

+ +
Application specific libraries. Basically, any kind of custom code that
+doesn't belong under controllers, models, or helpers. This directory is in
+the load path.
+ +

public

+ +
The directory available for the web server. Also contains the dispatchers and the
+default HTML files. This should be set as the DOCUMENT_ROOT of your web
+server.
+ +

script

+ +
Helper scripts for automation and generation.
+ +

test

+ +
Unit and functional tests along with fixtures. When using the rails generate
+command, template test files will be generated for you and placed in this
+directory.
+ +

vendor

+ +
External libraries that the application depends on. Also includes the plugins
+subdirectory. If the app has frozen rails, those gems also go here, under
+vendor/rails/. This directory is in the load path.
+
+ + + + + diff --git a/doc/app/RedirectHelper.html b/doc/app/RedirectHelper.html new file mode 100644 index 0000000000..d0e1fd4ed2 --- /dev/null +++ b/doc/app/RedirectHelper.html @@ -0,0 +1,95 @@ + + + + + + +module RedirectHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module RedirectHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Relationship.html b/doc/app/Relationship.html new file mode 100644 index 0000000000..8f59141874 --- /dev/null +++ b/doc/app/Relationship.html @@ -0,0 +1,102 @@ + + + + + + +class Relationship - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Relationship +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/RelationshipsController.html b/doc/app/RelationshipsController.html new file mode 100644 index 0000000000..26878a795e --- /dev/null +++ b/doc/app/RelationshipsController.html @@ -0,0 +1,192 @@ + + + + + + +class RelationshipsController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class RelationshipsController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/relationships_controller.rb, line 4
+def create
+  user = User.find(params[:followed_id])
+  current_user.follow(user)
+  redirect_to "/profile/#{user.username}"
+end
+
+ +
+ + + + +
+ + +
+ +
+ destroy() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/relationships_controller.rb, line 10
+def destroy
+  user = Relationship.find(params[:id]).followed
+  current_user.unfollow(user)
+  redirect_to "/profile/#{user.username}"
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/Revision.html b/doc/app/Revision.html new file mode 100644 index 0000000000..809779b477 --- /dev/null +++ b/doc/app/Revision.html @@ -0,0 +1,819 @@ + + + + + + +class Revision - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Revision +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ author() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 67
+def author
+  DrupalUser.find_by(uid: uid)
+end
+
+ +
+ + + + +
+ + +
+ +
+ body_extras(content) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 126
+def body_extras(content)
+  # inline edit button
+  content = content.gsub('[edit]', '<p class="well" style="padding:6px;"><a class="btn btn-primary" href="' + parent.edit_path + '"><i class="fa fa-white icon-pencil"></i> Edit this page</a> to help complete it!</p>')
+  # inline question button
+  content = content.gsub(/\[question:([\w-]+)\]/, '<p class="well" style="padding:6px;"><a style="margin-bottom:6px;" class="btn btn-primary" href="/post?tags=question:\1&template=question"><i class="fa fa-white icon-question-sign"></i> Ask a question about <b>\1</b></a> or <a style="margin-bottom:6px;" class="btn" target="_blank" href="/subscribe/tag/question:\1">Sign up to answer questions on this topic</a></p>')
+  # inline foldaway
+  content = content.gsub(/\[fold\:(.+)\]/, '<p class="foldaway-link" data-title="\1"><i style="color:#666;padding-right:3px;" class="fa fa-expand-alt"></i> <a>\1 &raquo;</a></p><div class="foldaway" data-title="\1">')
+  content = content.gsub('[unfold]', '</div>')
+  content
+end
+
+ +
+ + + + +
+ + +
+ +
+ body_preview(length = 100) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 111
+def body_preview(length = 100)
+  newBody = body.gsub(/^#+.+/, '')
+  newBody.truncate(length)
+end
+
+ +
+ + + + +
+ + +
+ +
+ body_raw() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 122
+def body_raw
+  body_extras(body)
+end
+
+ +
+ + + + +
+ + +
+ +
+ body_rich() + + click to toggle source + +
+ + +
+ +

some adaptations for the new rich editor

+ + + + +
+
# File app/models/revision.rb, line 117
+def body_rich
+  # turn ##Headers into ## Headers
+  body.gsub(/(^|\n)(#+)([A-z]+)/, '\1\2 \3')
+end
+
+ +
+ + + + +
+ + +
+ +
+ created_at() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 55
+def created_at
+  Time.at(timestamp)
+end
+
+ +
+ + + + +
+ + +
+ +
+ inline_hashtags() + + click to toggle source + +
+ + +
+ +

search for inline hashtags(such as hashtag) and create a new tag

+ + + + +
+
# File app/models/revision.rb, line 49
+def inline_hashtags
+  body.scan(Callouts.const_get(:HASHTAG)).each do |match|
+    parent.add_tag(match.last, author)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ inline_tags() + + click to toggle source + +
+ + +
+ +

search for inline special tags such as [question:foo]

+ + + + +
+
# File app/models/revision.rb, line 42
+def inline_tags
+  body.scan(/\[question(:[\w-]+)\]/).each do |match|
+    parent.add_tag('prompt' + match.first, author)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ is_initial?() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 75
+def is_initial?
+  parent.revision.count == 1
+end
+
+ +
+ + + + +
+ + +
+ +
+ next() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 85
+def next
+  parent.revision.order('timestamp DESC')
+        .where('timestamp > ?', timestamp)
+        .last
+end
+
+ +
+ + + + +
+ + +
+ +
+ parent() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 71
+def parent
+  node
+end
+
+ +
+ + + + +
+ + +
+ +
+ path() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 63
+def path
+  node.path
+end
+
+ +
+ + + + +
+ + +
+ +
+ previous() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 79
+def previous
+  parent.revision.order('timestamp DESC')
+        .where('timestamp < ?', timestamp)
+        .first
+end
+
+ +
+ + + + +
+ + +
+ +
+ publish() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 29
+def publish
+  self.status = 1
+  save
+  self
+end
+
+ +
+ + + + +
+ + +
+ +
+ render_body() + + click to toggle source + +
+ + +
+ +

filtered version of node content

+ + + + +
+
# File app/models/revision.rb, line 92
+def render_body
+  body = self.body || ''
+  body = RDiscount.new(body)
+  body = body.to_html
+  body = body.gsub(Callouts.const_get(:FINDER), Callouts.const_get(:PRETTYLINKHTML))
+  body = body.gsub(Callouts.const_get(:HASHTAGNUMBER), Callouts.const_get(:NODELINKHTML))
+  body = body.gsub(Callouts.const_get(:HASHTAG), Callouts.const_get(:HASHLINKHTML))
+  body_extras(body)
+end
+
+ +
+ + + + +
+ + +
+ +
+ render_body_email(host = 'publiclab.org') + + click to toggle source + +
+ + +
+ +

filtered version additionally appending http/https protocol to +protocol-relative URLs like “/foo” #render_body plus making all +relative links absolute

+ + + + +
+
# File app/models/revision.rb, line 104
+def render_body_email(host = 'publiclab.org')
+  body = render_body.gsub(/([\s|"|'|\[|\(])(\/\/)([\w]?\.?#{host})/, '\1https://\3')
+  body = body.gsub("href='/", "href='https://#{host}/")
+  body = body.gsub('href="/', 'href="https://' + host.to_s + '/')
+  body
+end
+
+ +
+ + + + +
+ + +
+ +
+ setup() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 22
+def setup
+  self.teaser = ''
+  self.log = ''
+  self.timestamp = DateTime.now.to_i
+  self.format = 1
+end
+
+ +
+ + + + +
+ + +
+ +
+ spam() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 35
+def spam
+  self.status = 0
+  save
+  self
+end
+
+ +
+ + + + +
+ + +
+ +
+ updated_at() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/revision.rb, line 59
+def updated_at
+  Time.at(timestamp)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/SearchRequest.html b/doc/app/SearchRequest.html new file mode 100644 index 0000000000..0fc8e4a2b6 --- /dev/null +++ b/doc/app/SearchRequest.html @@ -0,0 +1,314 @@ + + + + + + +class SearchRequest - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class SearchRequest +

+ +
+ +

Class encapsulating search requests.

+ +
+ + + + +
+ + + + + +
+
+

Constants

+
+
+ +
MIN_QUERY_LENGTH + +

Minimum query length, or we return an empty result

+ + +
+
+ + + +
+
+

Attributes

+
+ + +
+
+ pageNum[RW] +
+ +
+ + + +
+
+ +
+
+ seq[RW] +
+ +
+ + + +
+
+ +
+
+ showCount[RW] +
+ +
+ + + +
+
+ +
+
+ srchString[RW] +
+ +
+ + + +
+
+ +
+ + + +
+
+

Public Class Methods

+
+ + +
+ +
+ fromRequest(rparams) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/search_request.rb, line 10
+def self.fromRequest(rparams)
+  obj = new
+  obj.srchString = rparams[:srchString]
+  obj.seq = rparams[:seq]
+  obj.showCount = rparams[:showCount]
+  obj.pageNum = rparams[:pageNum]
+  obj
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/search_request.rb, line 8
+def initialize; end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ valid?() + + click to toggle source + +
+ + +
+ +

Check the query string to make sure it is not blank (null, empty string, or +' ') and make sure it is at least 3 characters

+ + + + +
+
# File app/models/search_request.rb, line 21
+def valid?
+  isValid = true
+  isValid &&= !srchString.blank?
+  isValid &&= srchString.length >= MIN_QUERY_LENGTH
+  isValid
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/SearchRequest/Entity.html b/doc/app/SearchRequest/Entity.html new file mode 100644 index 0000000000..392b5ae571 --- /dev/null +++ b/doc/app/SearchRequest/Entity.html @@ -0,0 +1,107 @@ + + + + + + +class SearchRequest::Entity - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class SearchRequest::Entity +

+ +
+ +

This subclass is used to auto-generate the RESTful data structure. It is +generally not useful for internal Ruby usage

+ +
but must be included for full RESTful functionality.
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/SearchService.html b/doc/app/SearchService.html new file mode 100644 index 0000000000..908a07ebca --- /dev/null +++ b/doc/app/SearchService.html @@ -0,0 +1,899 @@ + + + + + + +class SearchService - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class SearchService +

+ +
+ +

The SearchService class is a utility class +whose purpose is to provide detailed responses to queries within different +categories (record types, functionality, subsystems, etc). Though similar +in operation to the TypeaheadService, +the implementation is separate, in that the goal of the response is to +provide detailed results at a deep level. In effect, TypeaheadService provides pointers to +better searches, while SearchService +provides deep and detailed information. TODO: Refactor TypeaheadService and SearchService so that common functions come +from a higher level class?

+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 9
+def initialize; end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ comments() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 31
+def comments
+  @comments ||= find_comments(params)
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_comments(input, limit = 5) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 50
+def find_comments(input, limit = 5)
+  Comment.limit(limit)
+         .order('nid DESC')
+         .where('status = 1 AND comment LIKE ?', '%' + input + '%')
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_maps(input, limit = 5) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 70
+def find_maps(input, limit = 5)
+  Node.limit(limit)
+      .order('nid DESC')
+      .where('type = "map" AND node.status = 1 AND title LIKE ?', '%' + input + '%')
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_nodes(input, limit = 5) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 56
+def find_nodes(input, limit = 5)
+  Node.limit(limit)
+      .order('nid DESC')
+      .where('node.status = 1 AND title LIKE ?', '%' + input + '%')
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_notes(input, limit = 5) + + click to toggle source + +
+ + +
+ +

search for node title only FIXme with solr

+ + + + +
+
# File app/services/search_service.rb, line 64
+def find_notes(input, limit = 5)
+  Node.limit(limit)
+      .order('nid DESC')
+      .where('type = "note" AND node.status = 1 AND title LIKE ?', '%' + input + '%')
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_tags(input, limit = 5) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 42
+def find_tags(input, limit = 5)
+  Tag.includes(:node)
+     .references(:node)
+     .where('node.status = 1')
+     .limit(limit)
+     .where('name LIKE ?', '%' + input + '%')
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_users(input, limit = 10) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 35
+def find_users(input, limit = 10)
+  User.limit(limit)
+      .order('id DESC')
+      .where(status: 1)
+      .where('username LIKE ?', '%' + input + '%')
+end
+
+ +
+ + + + +
+ + +
+ +
+ maps(params) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 27
+def maps(params)
+  @maps ||= find_maps(params)
+end
+
+ +
+ + + + +
+ + +
+ +
+ nodes(params) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 19
+def nodes(params)
+  @nodes ||= find_nodes(params)
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes(params) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 23
+def notes(params)
+  @notes ||= find_notes(params)
+end
+
+ +
+ + + + +
+ + +
+ +
+ tags(params) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 15
+def tags(params)
+  @tags ||= find_tags(params)
+end
+
+ +
+ + + + +
+ + +
+ +
+ textSearch_all(srchString) + + click to toggle source + +
+ + +
+ +

Run a search in any of the associated systems for references that contain +the search string

+ + + + +
+
# File app/services/search_service.rb, line 77
+def textSearch_all(srchString)
+  sresult = DocList.new
+  unless srchString.nil? || srchString == 0
+    # notes
+    noteList = textSearch_notes(srchString)
+    sresult.addAll(noteList.items)
+
+    # Node search
+    Node.limit(5)
+        .order('nid DESC')
+        .where('(type = "page" OR type = "place" OR type = "tool") AND node.status = 1 AND title LIKE ?', '%' + srchString + '%')
+        .select('title,type,nid,path').each do |match|
+      doc = DocResult.fromSearch(match.nid, match.icon, match.path, match.title, '', 0)
+      sresult.addDoc(doc)
+    end
+    # User profiles
+    userList = textSearch_profiles(srchString)
+    sresult.addAll(userList.items)
+
+    # Tags
+    tagList = textSearch_tags(srchString)
+    sresult.addAll(tagList.items)
+    # maps
+    mapList = textSearch_maps(srchString)
+    sresult.addAll(mapList.items)
+    # questions
+    qList = textSearch_questions(srchString)
+    sresult.addAll(qList.items)
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ textSearch_maps(srchString) + + click to toggle source + +
+ + +
+ +

Search maps for matching text

+ + + + +
+
# File app/services/search_service.rb, line 136
+def textSearch_maps(srchString)
+  sresult = DocList.new
+  unless srchString.nil? || srchString == 0
+    # maps
+    maps(srchString).select('title,type,nid,path').each do |match|
+      doc = DocResult.fromSearch(match.nid, match.icon, match.path, match.title, '', 0)
+      sresult.addDoc(doc)
+    end
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ textSearch_notes(srchString) + + click to toggle source + +
+ + +
+ +

Search notes for matching strings

+ + + + +
+
# File app/services/search_service.rb, line 123
+def textSearch_notes(srchString)
+  sresult = DocList.new
+  unless srchString.nil? || srchString == 0
+    # notes
+    find_notes(srchString, 25).each do |match|
+      doc = DocResult.fromSearch(match.nid, 'file', match.path, match.title, match.body.split(/#+.+\n+/, 5)[1], 0)
+      sresult.addDoc(doc)
+    end
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ textSearch_profiles(srchString) + + click to toggle source + +
+ + +
+ +

Search profiles for matching text

+ + + + +
+
# File app/services/search_service.rb, line 110
+def textSearch_profiles(srchString)
+  sresult = DocList.new
+  unless srchString.nil? || srchString == 0
+    # User profiles
+    users(srchString).each do |match|
+      doc = DocResult.fromSearch(0, 'user', '/profile/' + match.name, match.name, '', 0)
+      sresult.addDoc(doc)
+    end
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ textSearch_questions(srchString) + + click to toggle source + +
+ + +
+ +

Search question entries for matching text

+ + + + +
+
# File app/services/search_service.rb, line 170
+def textSearch_questions(srchString)
+  sresult = DocList.new
+  questions = Node.where(
+    'type = "note" AND node.status = 1 AND title LIKE ?',
+    '%' + srchString + '%'
+  )
+                  .joins(:tag)
+                  .where('term_data.name LIKE ?', 'question:%')
+                  .order('node.nid DESC')
+                  .limit(25)
+  questions.each do |match|
+    doc = DocResult.fromSearch(match.nid, 'question-circle', match.path(:question), match.title, 0, match.answers.length.to_i)
+    sresult.addDoc(doc)
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ textSearch_tags(srchString) + + click to toggle source + +
+ + +
+ +

Search documents with matching tag values The search string that is passed +in is split into tokens, and the tag names are compared and chained to the +notes that are tagged with those values

+ + + + +
+
# File app/services/search_service.rb, line 151
+def textSearch_tags(srchString)
+  sresult = DocList.new
+  unless srchString.nil? || srchString == 0
+    # Tags
+    sterms = srchString.split(' ')
+    tlist = Tag.where(name: sterms)
+               .joins(:node_tag)
+               .joins(:node)
+               .where('node.status = 1')
+               .select('DISTINCT node.nid,node.title,node.path')
+    tlist.each do |match|
+      tagdoc = DocResult.fromSearch(match.nid, 'tag', match.path, match.title, '', 0)
+      sresult.addDoc(tagdoc)
+    end
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ users(params) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/search_service.rb, line 11
+def users(params)
+  @users ||= find_users(params)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/SearchesController.html b/doc/app/SearchesController.html new file mode 100644 index 0000000000..08ff220045 --- /dev/null +++ b/doc/app/SearchesController.html @@ -0,0 +1,226 @@ + + + + + + +class SearchesController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class SearchesController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ dynamic() + + click to toggle source + +
+ + +
+ +

Dynamic Search Page using pure JavaScript JSON RESTful API

+ + + + +
+
# File app/controllers/searches_controller.rb, line 6
+def dynamic
+  render :dynamic
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ +

/search/

+ + + + +
+
# File app/controllers/searches_controller.rb, line 11
+def new
+end
+
+ +
+ + + + +
+ + +
+ +
+ results() + + click to toggle source + +
+ + +
+ +

results: /search/foo

+ + + + +
+
# File app/controllers/searches_controller.rb, line 15
+def results
+  @title = 'Search'
+  @tagnames = params[:id].split(',')
+  @users = SearchService.new.users(params[:id])
+  @nodes = SearchService.new.nodes(params[:id])
+                            .paginate(page: params[:page], per_page: 24)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/SearchesHelper.html b/doc/app/SearchesHelper.html new file mode 100644 index 0000000000..3fa3d3d771 --- /dev/null +++ b/doc/app/SearchesHelper.html @@ -0,0 +1,95 @@ + + + + + + +module SearchesHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module SearchesHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/SettingsController.html b/doc/app/SettingsController.html new file mode 100644 index 0000000000..0458cd5ef6 --- /dev/null +++ b/doc/app/SettingsController.html @@ -0,0 +1,162 @@ + + + + + + +class SettingsController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class SettingsController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ change_locale() + + click to toggle source + +
+ + +
+ +

Check the locale was passed and if it is a valid one, set the locale in +cookies

+ + + + +
+
# File app/controllers/settings_controller.rb, line 3
+def change_locale
+  lang = params[:locale].to_s.strip.to_sym
+  lang = I18n.default_locale unless I18n.available_locales.include?(lang)
+  cookies.permanent[:plots2_locale] = lang
+  I18n.locale = lang
+  if request.referer
+    redirect_to request.referer + '?_=' + Time.now.to_i.to_s
+  else
+    redirect_to root_url
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/SolrToggle.html b/doc/app/SolrToggle.html new file mode 100644 index 0000000000..bdff39f8c2 --- /dev/null +++ b/doc/app/SolrToggle.html @@ -0,0 +1,196 @@ + + + + + + +module SolrToggle - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module SolrToggle +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ shouldIndexSolr() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/solr_toggle/solr_toggle.rb, line 3
+def shouldIndexSolr
+  if ENV["DISABLE_SOLR_CHECK"]
+    true
+  else
+    solrAvailable
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ solrAvailable() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File lib/solr_toggle/solr_toggle.rb, line 11
+def solrAvailable
+  begin
+    if !Sunspot::Rails.configuration.disabled?
+      Node.search do
+        fulltext 'test' # just see if we break things
+      end
+      true
+    else
+      false
+    end
+  rescue
+    false
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/Spamaway.html b/doc/app/Spamaway.html new file mode 100644 index 0000000000..3f091fc6e3 --- /dev/null +++ b/doc/app/Spamaway.html @@ -0,0 +1,242 @@ + + + + + + +class Spamaway - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Spamaway +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ get_pairs(how_many) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/spamaway.rb, line 20
+def self.get_pairs(how_many)
+  @human = [I18n.t('spamaway.human.statement1'),
+            I18n.t('spamaway.human.statement2'),
+            I18n.t('spamaway.human.statement3'),
+            I18n.t('spamaway.human.statement4'),
+            I18n.t('spamaway.human.statement5'),
+            I18n.t('spamaway.human.statement6')]
+
+  @robot = [I18n.t('spamaway.robot.statement1'),
+            I18n.t('spamaway.robot.statement2'),
+            I18n.t('spamaway.robot.statement3'),
+            I18n.t('spamaway.robot.statement4'),
+            I18n.t('spamaway.robot.statement5'),
+            I18n.t('spamaway.robot.statement6')]
+
+  # static method to return how_many pairs of human/robot statements.
+  if (how_many <= 0) || (how_many > @human.length) || (how_many > @robot.length)
+    raise ArgumentError, 'Cannot return ' + how_many + ' statements.'
+  end
+
+  # randomly select how_many statements from each list
+  human_perms = @human.permutation(how_many).to_a
+  robot_perms = @robot.permutation(how_many).to_a
+  human_index = rand(human_perms.length)
+  robot_index = rand(robot_perms.length)
+
+  # slap pairs together
+  pairs = human_perms[human_index].zip(robot_perms[robot_index])
+  # randomly flip human/robot order for each statement pair
+  pairs.each_index do |i|
+    pairs[i] = pairs[i].permutation.to_a[rand * 2]
+  end
+  pairs
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ human_response?(response) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/spamaway.rb, line 55
+def human_response?(response)
+  @human = [I18n.t('spamaway.human.statement1'),
+            I18n.t('spamaway.human.statement2'),
+            I18n.t('spamaway.human.statement3'),
+            I18n.t('spamaway.human.statement4'),
+            I18n.t('spamaway.human.statement5'),
+            I18n.t('spamaway.human.statement6')]
+
+  @robot = [I18n.t('spamaway.robot.statement1'),
+            I18n.t('spamaway.robot.statement2'),
+            I18n.t('spamaway.robot.statement3'),
+            I18n.t('spamaway.robot.statement4'),
+            I18n.t('spamaway.robot.statement5'),
+            I18n.t('spamaway.robot.statement6')]
+
+  # return True if response is a human response, False otherwise.
+  @human.member? response
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/Srch.html b/doc/app/Srch.html new file mode 100644 index 0000000000..52e177b11f --- /dev/null +++ b/doc/app/Srch.html @@ -0,0 +1,95 @@ + + + + + + +module Srch - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module Srch +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Srch/API.html b/doc/app/Srch/API.html new file mode 100644 index 0000000000..179c9accb6 --- /dev/null +++ b/doc/app/Srch/API.html @@ -0,0 +1,102 @@ + + + + + + +class Srch::API - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Srch::API +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Srch/API/DocList.html b/doc/app/Srch/API/DocList.html new file mode 100644 index 0000000000..508f1bebfd --- /dev/null +++ b/doc/app/Srch/API/DocList.html @@ -0,0 +1,95 @@ + + + + + + +module Srch::API::DocList - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module Srch::API::DocList +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Srch/API/DocResult.html b/doc/app/Srch/API/DocResult.html new file mode 100644 index 0000000000..0e756132f4 --- /dev/null +++ b/doc/app/Srch/API/DocResult.html @@ -0,0 +1,95 @@ + + + + + + +module Srch::API::DocResult - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module Srch::API::DocResult +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Srch/API/SearchRequest.html b/doc/app/Srch/API/SearchRequest.html new file mode 100644 index 0000000000..3a4bba5747 --- /dev/null +++ b/doc/app/Srch/API/SearchRequest.html @@ -0,0 +1,95 @@ + + + + + + +module Srch::API::SearchRequest - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module Srch::API::SearchRequest +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Srch/API/TagList.html b/doc/app/Srch/API/TagList.html new file mode 100644 index 0000000000..f6b8c6f30a --- /dev/null +++ b/doc/app/Srch/API/TagList.html @@ -0,0 +1,95 @@ + + + + + + +module Srch::API::TagList - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module Srch::API::TagList +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Srch/API/TagResult.html b/doc/app/Srch/API/TagResult.html new file mode 100644 index 0000000000..255871f81e --- /dev/null +++ b/doc/app/Srch/API/TagResult.html @@ -0,0 +1,95 @@ + + + + + + +module Srch::API::TagResult - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module Srch::API::TagResult +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Srch/Search.html b/doc/app/Srch/Search.html new file mode 100644 index 0000000000..25847c06f6 --- /dev/null +++ b/doc/app/Srch/Search.html @@ -0,0 +1,102 @@ + + + + + + +class Srch::Search - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Srch::Search +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/Srch/Typeahead.html b/doc/app/Srch/Typeahead.html new file mode 100644 index 0000000000..803f377200 --- /dev/null +++ b/doc/app/Srch/Typeahead.html @@ -0,0 +1,116 @@ + + + + + + +class Srch::Typeahead - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Srch::Typeahead +

+ +
+ +
+ + + + +
+ + + + + +
+
+

Constants

+
+
+ +
TYPEAHEAD_LIMIT + +

Number of top values of each type to return

+ + +
+
+ + + + + +
+
+ + + + diff --git a/doc/app/Srch/Typeahead/TagList.html b/doc/app/Srch/Typeahead/TagList.html new file mode 100644 index 0000000000..09473e0b45 --- /dev/null +++ b/doc/app/Srch/Typeahead/TagList.html @@ -0,0 +1,95 @@ + + + + + + +module Srch::Typeahead::TagList - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module Srch::Typeahead::TagList +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/StatsController.html b/doc/app/StatsController.html new file mode 100644 index 0000000000..7886803325 --- /dev/null +++ b/doc/app/StatsController.html @@ -0,0 +1,295 @@ + + + + + + +class StatsController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class StatsController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/stats_controller.rb, line 34
+def index
+  @time = if params[:time]
+            Time.parse(params[:time])
+          else
+            Time.now
+          end
+
+  @weekly_notes = Node.select(%[created type status])
+                      .where(type: 'note', status: 1, created: @time.to_i - 1.weeks.to_i..@time.to_i)
+                      .count(:all)
+  @weekly_wikis = Revision.select(:timestamp)
+                          .where(timestamp: @time.to_i - 1.weeks.to_i..@time.to_i)
+                          .count
+  @weekly_members = User.where(created_at: @time - 1.weeks..@time)
+                        .joins('INNER JOIN users ON users.uid = rusers.id')
+                        .where('users.status = 1')
+                        .count
+  @monthly_notes = Node.select(%[created type status])
+                       .where(type: 'note', status: 1, created: @time.to_i - 1.months.to_i..@time.to_i)
+                       .count(:all)
+  @monthly_wikis = Revision.select(:timestamp)
+                           .where(timestamp: @time.to_i - 1.months.to_i..@time.to_i)
+                           .count
+  @monthly_members = User.where(created_at: @time - 1.months..@time)
+                         .joins('INNER JOIN users ON users.uid = rusers.id')
+                         .where('users.status = 1')
+                         .count
+
+  @notes_per_week_past_year = Node.select(%[created type status])
+                                  .where(type: 'note', status: 1, created: @time.to_i - 1.years.to_i..@time.to_i)
+                                  .count(:all) / 52.0
+  @edits_per_week_past_year = Revision.select(:timestamp)
+                                      .where(timestamp: @time.to_i - 1.years.to_i..@time.to_i)
+                                      .count / 52.0
+
+  @graph_notes = Node.weekly_tallies('note', 52, @time).to_a.sort.to_json
+  @graph_wikis = Node.weekly_tallies('page', 52, @time).to_a.sort.to_json
+  @graph_comments = Comment.comment_weekly_tallies(52, @time).to_a.sort.to_json
+
+  users = []
+  nids = []
+  Node.where(type: 'note', status: 1).each do |note|
+    unless note.uid == 674 || note.uid == 671
+      users << note.uid
+      nids << note.nid
+    end
+  end
+
+  @all_notes = nids.uniq.length
+  @all_contributors = users.uniq.length
+end
+
+ +
+ + + + +
+ + +
+ +
+ range() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/stats_controller.rb, line 11
+def range
+  @start = params[:start] ? Time.parse(params[:start]) : Time.now - 1.month
+  @end = params[:end] ? Time.parse(params[:end]) : Time.now
+  @notes = Node.select(%[created type status])
+               .where(type: 'note', status: 1, created: @start.to_i..@end.to_i)
+               .count(:all)
+  @wikis = Revision.select(:timestamp)
+                   .where(timestamp: @start.to_i..@end.to_i)
+                   .count - @notes # because notes each have one revision
+  @people = User.where(created_at: @start..@end)
+                .joins('INNER JOIN users ON users.uid = rusers.id')
+                .where('users.status = 1')
+                .count                 
+  @answers = Answer.where(created_at: @start..@end)
+                   .count
+  @comments = Comment.select(:timestamp)
+                     .where(timestamp: @start.to_i..@end.to_i)
+                     .count
+  @questions = Node.questions.where(status: 1, created: @start.to_i..@end.to_i)
+                   .count
+  @contributors = User.contributor_count_for(@start,@end)
+end
+
+ +
+ + + + +
+ + +
+ +
+ subscriptions() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/stats_controller.rb, line 2
+def subscriptions
+  @tags = {}
+  TagSelection.where(following: true).each do |tag|
+    @tags[tag.tagname] = @tags[tag.tagname] || 0
+    @tags[tag.tagname] += 1
+  end
+  render text: @tags.inspect, status: 200
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/SubscriptionController.html b/doc/app/SubscriptionController.html new file mode 100644 index 0000000000..b86fd6f4e2 --- /dev/null +++ b/doc/app/SubscriptionController.html @@ -0,0 +1,375 @@ + + + + + + +class SubscriptionController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class SubscriptionController +

+ +
+ +

for now, adapting like_controller for just tag following. We can create +switches for different kinds of likes. No route or view code as of yet.

+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ add() + + click to toggle source + +
+ + +
+ +

for the current user, register as liking the given tag

+ + + + +
+
# File app/controllers/subscription_controller.rb, line 33
+def add
+  if current_user
+    # assume tag, for now
+    if params[:type] == "tag"
+      tag = Tag.find_by(name: params[:name])
+      if tag.nil?
+        # if the tag doesn't exist, we should create it!
+        # this could fail validations; error out if so... 
+        tag = Tag.new({
+          :vid => 3, # vocabulary id
+          :name => params[:name],
+          :description => "",
+          :weight => 0})
+        begin
+          tag.save!
+        rescue ActiveRecord::RecordInvalid
+          flash[:error] = tag.errors.full_messages
+          redirect_to "/subscriptions" + "?_=" + Time.now.to_i.to_s
+          return false
+        end
+      end
+
+      # test for uniqueness, handle it as a validation error if you like
+      if TagSelection.where(following: true, user_id: current_user.uid, tid: tag.tid).length > 0
+        flash[:error] = "You are already subscribed to '#{params[:name]}'"
+        redirect_to "/subscriptions" + "?_=" + Time.now.to_i.to_s
+      else
+        if set_following(true,params[:type],tag.tid)
+          respond_with do |format|
+            format.html do
+              if request.xhr?
+                render :json => true
+              else
+                flash[:notice] = "You are now following '#{params[:name]}'."
+                redirect_to "/subscriptions" + "?_=" + Time.now.to_i.to_s
+              end
+            end
+          end
+        else
+          flash[:error] = "Something went wrong!" # silly 
+        end
+      end
+    else
+      # user or node subscription
+
+    end
+  else
+      flash[:warning] = "You must be logged in to subscribe for email updates; please <a href='javascript:void()' onClick='login()'>log in</a> or <a href='/signup'>create an account</a>."
+      redirect_to "/tag/"+params[:name]
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ +

for the current user, remove the like from the given tag

+ + + + +
+
# File app/controllers/subscription_controller.rb, line 86
+def delete
+  # assume tag, for now
+  if params[:type] == "tag"
+    id = Tag.find_by(name: params[:name]).tid
+  end
+  if id.nil?
+    flash[:error] = "You are not subscribed to '#{params[:name]}'"
+    redirect_to "/subscriptions" + "?_=" + Time.now.to_i.to_s
+  else
+    if !set_following(false,params[:type],id) #should return false if result is that following == false
+      respond_with do |format|
+        format.html do
+          if request.xhr?
+            render :json => true
+          else
+            flash[:notice] = "You have stopped following '#{params[:name]}'."
+            redirect_to "/subscriptions" + "?_=" + Time.now.to_i.to_s
+          end
+        end
+      end
+    else
+      flash[:error] = "Something went wrong!" # silly 
+      redirect_to "/subscriptions" + "?_=" + Time.now.to_i.to_s
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ followed() + + click to toggle source + +
+ + +
+ +

for the current user, return whether is presently liked or not

+ + + + +
+
# File app/controllers/subscription_controller.rb, line 21
+def followed
+  # may be trouble: there can be multiple tags with the same name, no? We can eliminate that possibility in a migration if so.
+  result = TagSelection.find_by_user_id_and_tid(current_user.uid, params[:id]) if params[:type] == "tag"
+  if result.nil?
+    result = false
+  else
+    result = result.following
+  end
+  render :json => result
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/subscription_controller.rb, line 10
+def index
+  @title = "Subscriptions"
+  render :template => "home/subscriptions"
+end
+
+ +
+ + + + +
+ + +
+ +
+ tag_count() + + click to toggle source + +
+ + +
+ +

return a count of subscriptions for a given tag

+ + + + +
+
# File app/controllers/subscription_controller.rb, line 16
+def tag_count
+  render json: TagSelection.where(tid: params[:tid], following: true)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/SubscriptionMailer.html b/doc/app/SubscriptionMailer.html new file mode 100644 index 0000000000..8021f52705 --- /dev/null +++ b/doc/app/SubscriptionMailer.html @@ -0,0 +1,266 @@ + + + + + + +class SubscriptionMailer - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class SubscriptionMailer +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ notify_node_creation(node) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/subscription_mailer.rb, line 6
+def notify_node_creation(node)
+  subject = '[PublicLab] ' + (node.has_power_tag('question') ? 'Question: ' : '') +
+            node.title
+  Tag.subscribers(node.tags).each do |_key, val|
+    @user = val[:user]
+    @node = node
+    @tags = val[:tags]
+    @footer = feature('email-footer')
+    mail(to: val[:user].email, subject: subject).deliver
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_note_liked(node, user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/subscription_mailer.rb, line 18
+def notify_note_liked(node, user)
+  subject = "[PublicLab] #{user.username} liked your " +
+            (node.has_power_tag('question') ? 'question' : 'research note')
+  @user = user
+  @node = node
+  @footer = feature('email-footer')
+  mail(to: node.author.email, subject: subject).deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+ notify_tag_added(node, tag, current_user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/mailers/subscription_mailer.rb, line 27
+def notify_tag_added(node, tag, current_user)
+   @tag = tag
+   @node = node
+   @current_user = current_user
+   given_tags = node.tags.reject { |t| t == tag} 
+   users_to_email = tag.followers_who_dont_follow_tags(given_tags)
+   users_with_everything_tag = Tag.followers('everything')
+   final_users_ids = nil 
+   if(!users_to_email.nil? && !users_with_everything_tag.nil?)
+     final_users_ids = users_to_email.collect(&:id) - users_with_everything_tag.collect(&:uid)
+   elsif(!users_to_email.nil?) 
+     final_users_ids = users_to_email.collect(&:id)
+   end
+   final_users_to_email = User.find(final_users_ids) 
+   final_users_to_email.each do |user|
+     @user = user
+     unless user.id == current_user.id 
+        mail(to: user.email, subject: "New tag added on #{node.title}").deliver 
+     end
+   end
+   @footer = feature('email-footer')
+ end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/Tableless.html b/doc/app/Tableless.html new file mode 100644 index 0000000000..2975457946 --- /dev/null +++ b/doc/app/Tableless.html @@ -0,0 +1,236 @@ + + + + + + +class Tableless - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Tableless +

+ +
+ +

stackoverflow.com/questions/937429/activerecordbase-without-table +Models without Tables

+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ column(name, sql_type = nil, default = nil, null = true) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tableless.rb, line 9
+def self.column(name, sql_type = nil, default = nil, null = true)
+  columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default,
+                                                          sql_type.to_s, null)
+end
+
+ +
+ + + + +
+ + +
+ +
+ columns() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tableless.rb, line 5
+def self.columns
+  @columns ||= []
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ save(validate = true) + + click to toggle source + +
+ + +
+ +

Override the save method to prevent exceptions.

+ + + + +
+
# File app/models/tableless.rb, line 15
+def save(validate = true)
+  validate ? valid? : true
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/Tag.html b/doc/app/Tag.html new file mode 100644 index 0000000000..8f2d25fcb4 --- /dev/null +++ b/doc/app/Tag.html @@ -0,0 +1,1063 @@ + + + + + + +class Tag - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class Tag +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ contributor_count(tagname) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 55
+def self.contributor_count(tagname)
+  tag = Tag.includes(:node).where(name: tagname).first
+  nodes = tag.node.includes(:revision, :comments,:answers).where(status: 1)
+  uids = nodes.collect(&:uid)
+  nodes.each do |n|
+    uids+=n.comments.collect(&:uid)
+    uids+=n.answers.collect(&:uid)
+    uids+=n.revision.collect(&:uid)
+  end
+  uids = uids.uniq
+  uids.length
+end
+
+ +
+ + + + +
+ + +
+ +
+ exists?(tagname, nid) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 135
+def self.exists?(tagname, nid)
+  !NodeTag.where('nid = ? AND term_data.name = ?', nid, tagname)
+                         .joins(:tag).empty?
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_nodes_by_type(tagnames, type = 'note', limit = 10) + + click to toggle source + +
+ + +
+ +

finds recent nodes - should drop “limit” and allow use of chainable +.limit()

+ + + + +
+
# File app/models/tag.rb, line 79
+def self.find_nodes_by_type(tagnames, type = 'note', limit = 10)
+  nodes = Node.where(status: 1, type: type)
+              .includes(:tag)
+              .references(:term_data)
+              .where('term_data.name IN (?)', tagnames)
+              #.select(%i[node.nid node.status node.type community_tags.nid community_tags.tid term_data.name term_data.tid])
+              # above select could be added later for further optimization
+  # .where('term_data.name IN (?) OR term_data.parent in (?)', tagnames, tagnames) # greedily fetch children
+  tags = Tag.where('term_data.name IN (?)', tagnames)
+  parents = Node.where(status: 1, type: type)
+                .includes(:tag)
+                .references(:term_data)
+                .where('term_data.name IN (?)', tags.collect(&:parent))
+  Node.where('node.nid IN (?)', (nodes + parents).collect(&:nid))
+      .includes(:revision, :tag)
+      .references(:node_revisions)
+      .where(status: 1)
+      .order('node_revisions.timestamp DESC')
+      .limit(limit)
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_nodes_by_type_with_all_tags(tagnames, type = 'note', limit = 10) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 105
+def self.find_nodes_by_type_with_all_tags(tagnames, type = 'note', limit = 10)
+  nids = []
+  tagnames.each do |tagname|
+    # tids = Tag.where('term_data.name IN (?) OR term_data.parent IN (?)', tagnames, tagnames) # greedily fetch children
+    tids = Tag.where('term_data.name IN (?)', tagnames)
+              .collect(&:tid)
+    tag_nids = NodeTag.where('tid IN (?)', tids)
+                                     .collect(&:nid)
+    tag = Tag.where(name: tagname).last
+    next unless tag
+    parents = Node.where(status: 1, type: type)
+                  .includes(:revision, :tag)
+                  .references(:term_data)
+                  .where('term_data.name LIKE ?', tag.parent)
+    nids += tag_nids + parents.collect(&:nid)
+  end
+  Node.where('nid IN (?)', nids)
+      .order('nid DESC')
+      .limit(limit)
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_pages(tagnames, limit = 10) + + click to toggle source + +
+ + +
+ +

just like ::find_nodes_by_type, but +searches wiki pages, places, and tools

+ + + + +
+
# File app/models/tag.rb, line 101
+def self.find_pages(tagnames, limit = 10)
+  find_nodes_by_type(tagnames, %w[page place tool], limit)
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+ find_research_notes(tagnames, limit = 10) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 212
+def self.find_research_notes(tagnames, limit = 10)
+  Node.research_notes.where(status: 1)
+      .includes(:revision, :tag)
+      .references(:node_revisions)
+      .where('term_data.name IN (?)', tagnames)
+      .order('node_revisions.timestamp DESC')
+      .limit(limit)
+end
+
+ +
+ + + + +
+ + +
+ +
+ find_top_nodes_by_type(tagname, type = 'wiki', limit = 10) + + click to toggle source + +
+ + +
+ +

finds highest viewcount nodes

+ + + + +
+
# File app/models/tag.rb, line 69
+def self.find_top_nodes_by_type(tagname, type = 'wiki', limit = 10)
+  Node.where(type: type)
+      .where('term_data.name = ?', tagname)
+      .order('node.views DESC')
+      .limit(limit)
+      .includes(:node_tag, :tag)
+      .references(:term_data)
+end
+
+ +
+ + + + +
+ + +
+ +
+ follower_count(tagname) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 144
+def self.follower_count(tagname)
+  TagSelection.joins(:tag)
+              .where('term_data.name = ? AND following = ?', tagname, true)
+              .count
+end
+
+ +
+ + + + +
+ + +
+ +
+ followers(tagname) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 150
+def self.followers(tagname)
+  uids = TagSelection.joins(:tag)
+                     .where('term_data.name = ? AND following = ?', tagname, true)
+                     .collect(&:user_id)
+  User.where(id: uids)
+      .where(status: [1, 4])
+end
+
+ +
+ + + + +
+ + +
+ +
+ is_powertag?(tagname) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 140
+def self.is_powertag?(tagname)
+  !tagname.match(':').nil?
+end
+
+ +
+ + + + +
+ + +
+ +
+ nodes_for_period(type, nids, start, finish) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 176
+def self.nodes_for_period(type, nids, start, finish)
+  Node.select(%[created status type nid])
+      .where(
+        'type = ? AND status = 1 AND nid IN (?) AND created > ? AND created <= ?',
+        type,
+        nids.uniq,
+        start,
+        finish
+      )
+end
+
+ +
+ + + + +
+ + +
+ +
+ subscribers(tags) + + click to toggle source + +
+ + +
+ +

Given a set of tags, return all users following those tags. Return a +dictionary of tags indexed by user. Accepts array of Tags, outputs array of +users as: {user: <user>, tags: [<tags>]} Used in +subscription_mailer

+ + + + +
+
# File app/models/tag.rb, line 192
+def self.subscribers(tags)
+  tids = tags.collect(&:tid)
+  # include special tid for indiscriminant subscribers who want it all!
+  all_tag = Tag.find_by(name: 'everything')
+  tids += [all_tag.tid] if all_tag
+  usertags = TagSelection.where('tid IN (?) AND following = ?', tids, true)
+  d = {}
+  usertags.each do |usertag|
+    # For each row of (user,tag), build a user's tag subscriptions
+    if (usertag.tid == all_tag) && usertag.tag.nil?
+      puts 'WARNING: all_tag tid ' + String(all_tag) + ' not found for Tag! Please correct this!'
+      next
+    end
+    d[usertag.user.name] = { user: usertag.user }
+    d[usertag.user.name][:tags] = Set.new if d[usertag.user.name][:tags].nil?
+    d[usertag.user.name][:tags].add(usertag.tag)
+  end
+  d
+end
+
+ +
+ + + + +
+ + +
+ +
+ tagged_nodes_by_author(tagname, user_id) + + click to toggle source + +
+ + +
+ +

select nodes by tagname and user_id

+ + + + +
+
# File app/models/tag.rb, line 240
+def self.tagged_nodes_by_author(tagname, user_id)
+  if tagname[-1..-1] == '*'
+    @wildcard = true
+    Node.where('term_data.name LIKE(?)', tagname[0..-2]+'%')
+      .includes(:node_tag, :tag)
+      .references(:term_data)
+      .where('node.uid = ?', user_id)
+  else
+    Node.where('term_data.name = ?', tagname)
+      .includes(:node_tag, :tag)
+      .references(:term_data)
+      .where('node.uid = ?', user_id)
+  end
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ belongs_to(current_user, nid) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 50
+def belongs_to(current_user, nid)
+  node_tag = node_tag.find_by(nid: nid)
+  node_tag && node_tag.uid == current_user.uid || node_tag.node.uid == current_user.uid
+end
+
+ +
+ + + + +
+ + +
+ +
+ filter_by_type(type, limit = 10) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 11
+def filter_by_type(type, limit = 10)
+  where(status: 1, type: type)
+    .limit(limit)
+    .order('created DESC')
+end
+
+ +
+ + + + +
+ + +
+ +
+ followers_who_dont_follow_tags(tags) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 221
+def followers_who_dont_follow_tags(tags)
+  tag_followers = User.where(id: self.subscriptions.collect(&:user_id))
+  uids = tags.collect(&:subscriptions).flatten.collect(&:user_id)
+  following_given_tags = User.where(id: uids)
+  tag_followers.reject { |user| following_given_tags.include? user  }
+end
+
+ +
+ + + + +
+ + +
+ +
+ id() + + click to toggle source + +
+ + +
+ +

validates :name, :uniqueness => { case_sensitive: false }

+ + + + +
+
# File app/models/tag.rb, line 32
+def id
+  tid
+end
+
+ +
+ + + + +
+ + +
+ +
+ nodes() + + click to toggle source + +
+ + +
+ +

nodes this tag has been used on; no wildcards

+ + + + +
+
# File app/models/tag.rb, line 46
+def nodes
+  nodes = Node.where(nid: node_tag.collect(&:nid))
+end
+
+ +
+ + + + +
+ + +
+ +
+ run_count() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 36
+def run_count
+  self.count = NodeTag.where(tid: tid).count
+  save
+end
+
+ +
+ + + + +
+ + +
+ +
+ subscriptions() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag.rb, line 41
+def subscriptions
+  tag_selection.where(following: true)
+end
+
+ +
+ + + + +
+ + +
+ +
+ weekly_tallies(type = 'note', span = 52) + + click to toggle source + +
+ + +
+ +

OPTIMIZE: this too!

+ + + + +
+
# File app/models/tag.rb, line 159
+def weekly_tallies(type = 'note', span = 52)
+  weeks = {}
+  tids = Tag.where('name IN (?)', [name])
+            .collect(&:tid)
+  nids = NodeTag.where('tid IN (?)', tids)
+                               .collect(&:nid)
+  (1..span).each do |week|
+    weeks[span - week] = Tag.nodes_for_period(
+      type,
+      nids,
+      (Time.now.to_i - week.weeks.to_i).to_s,
+      (Time.now.to_i - (week - 1).weeks.to_i).to_s
+    ).count(:all)
+  end
+  weeks
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/TagController.html b/doc/app/TagController.html new file mode 100644 index 0000000000..b1d803188a --- /dev/null +++ b/doc/app/TagController.html @@ -0,0 +1,943 @@ + + + + + + +class TagController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class TagController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ author() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 162
+def author
+  render json: DrupalUser.find_by(name: params[:id]).tag_counts
+end
+
+ +
+ + + + +
+ + +
+ +
+ barnstar() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 166
+def barnstar
+  node = Node.find params[:nid]
+  tagname = 'barnstar:' + params[:star]
+  if Tag.exists?(tagname, params[:nid])
+    flash[:error] = I18n.t('tag_controller.tag_already_exists')
+  elsif !node.add_barnstar(tagname.strip, current_user)
+    flash[:error] = I18n.t('tag_controller.barnstar_not_created')
+  else
+    flash[:notice] = I18n.t('tag_controller.barnstar_awarded', url1: '/wiki/barnstars#' + params[:star].split('-').each(&:capitalize!).join('+') + '+Barnstar', star: params[:star], url2: '/profile/' + node.author.name, awardee: node.author.name).html_safe
+    # on success add comment
+    barnstar_info_link = '<a href="//' + request.host.to_s + '/wiki/barnstars">barnstar</a>'
+    node.add_comment(subject: 'barnstar',
+                     uid: current_user.uid,
+                     body: "@#{current_user.username} awards a #{barnstar_info_link} to #{node.drupal_user.name} for their awesome contribution!")
+  end
+  redirect_to node.path + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ blog() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 152
+def blog
+  nids = Tag.find_nodes_by_type(params[:id], 'note', 20).collect(&:nid)
+  @notes = Node.paginate(page: params[:page], per_page: 6)
+               .where('status = 1 AND nid in (?)', nids)
+               .order('nid DESC')
+  @tags = Tag.where(name: params[:id])
+  @tagnames = @tags.collect(&:name).uniq! || []
+  @title = @tagnames.join(',') + ' Blog' if @tagnames
+end
+
+ +
+ + + + +
+ + +
+ +
+ contributors() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 292
+def contributors
+  set_sidebar :tags, [params[:id]], note_count: 20
+  @tagnames = [params[:id]]
+  @tag = Tag.find_by(name: params[:id])
+  @notes = Node.where(status: 1, type: 'note')
+               .includes(:revision, :tag)
+               .references(:term_data, :node_revisions)
+               .where('term_data.name = ?', params[:id])
+               .order('node_revisions.timestamp DESC')
+  @users = @notes.collect(&:author).uniq
+end
+
+ +
+ + + + +
+ + +
+ +
+ contributors_index() + + click to toggle source + +
+ + +
+ +

/contributors

+ + + + +
+
# File app/controllers/tag_controller.rb, line 305
+def contributors_index
+  @tagnames = ['balloon-mapping', 'spectrometer', 'infragram', 'air-quality', 'water-quality']
+  @tagdata = {}
+  @tags = []
+
+  @tagnames.each do |tagname|
+    tag = Tag.find_by(name: tagname)
+    @tags << tag if tag
+    @tagdata[tagname] = {}
+    t = Tag.where(name: tagname)
+    nct = NodeTag.where('tid in (?)', t.collect(&:tid))
+    @tagdata[tagname][:users] = Node.where('nid IN (?)', nct.collect(&:nid)).collect(&:author).uniq.length
+    @tagdata[tagname][:wikis] = Node.where("nid IN (?) AND (type = 'page' OR type = 'tool' OR type = 'place')", nct.collect(&:nid)).count
+    @tagdata[:notes] = Node.where("nid IN (?) AND type = 'note'", nct.collect(&:nid)).count
+  end
+  render template: 'tag/contributors-index'
+end
+
+ +
+ + + + +
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 184
+def create
+  params[:name] ||= ''
+  tagnames = params[:name].split(',')
+  @output = {
+    errors: [],
+    saved: []
+  }
+  @tags = [] # not used except in tests for now
+
+  nid = params[:nid] || params[:id]
+  node = Node.find nid
+  tagnames.each do |tagname|
+    # this should all be done in the model:
+
+    if Tag.exists?(tagname, nid)
+      @output[:errors] << I18n.t('tag_controller.tag_already_exists')
+    elsif node.can_tag(tagname, current_user) === true || current_user.role == 'admin' # || current_user.role == "moderator"
+      saved, tag = node.add_tag(tagname.strip, current_user)
+      if saved
+        @tags << tag
+        @output[:saved] << [tag.name, tag.id]
+      else
+        @output[:errors] << I18n.t('tag_controller.error_tags') + tag.errors[:name].first
+      end
+    else
+      @output[:errors] << node.can_tag(tagname, current_user, true)
+    end
+
+  end
+  respond_with do |format|
+    format.html do
+      if request.xhr?
+        render json: @output
+      else
+        flash[:notice] = I18n.t('tag_controller.tags_created_error',
+                                tag_count: @output[:saved].length,
+                                error_count: @output[:errors].length).html_safe
+        redirect_to node.path
+      end
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ +

should delete only the term_node/node_tag (instance), not the term_data +(class)

+ + + + +
+
# File app/controllers/tag_controller.rb, line 228
+def delete
+  node_tag = NodeTag.where(nid: params[:nid], tid: params[:tid]).first
+  # only admins, mods, and tag authors can delete other peoples' tags
+  if node_tag.uid == current_user.uid || current_user.role == 'admin' || current_user.role == 'moderator'
+
+    node_tag.delete
+    respond_with do |format|
+      format.html do
+        if request.xhr?
+          render text: node_tag.tid
+        else
+          flash[:notice] = I18n.t('tag_controller.tag_deleted')
+          redirect_to node_tag.node.path
+        end
+      end
+    end
+  else
+    flash[:error] = I18n.t('tag_controller.must_own_tag_to_delete')
+    redirect_to Node.find_by(nid: params[:nid]).path
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ gridsEmbed() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 331
+def gridsEmbed
+  render layout: false
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 5
+def index
+  if params[:format]
+    @toggle = params[:format].to_i
+  else
+    @toggle = 1
+  end
+
+  @title = I18n.t('tag_controller.tags')
+  @paginated = true
+  if params[:search]
+  prefix = params[:search]
+  @tags = Tag.joins(:node_tag, :node)
+             .select('node.nid, node.status, term_data.*, community_tags.*')
+             .where('node.status = ?', 1)
+             .where('community_tags.date > ?', (DateTime.now - 1.month).to_i)
+             .where("name LIKE :prefix", prefix: "#{prefix}%")
+             .group(:name)
+             .order('count DESC')
+             .paginate(page: params[:page], per_page: 24)
+  elsif @toggle == 1
+  @tags = Tag.joins(:node_tag, :node)
+             .select('node.nid, node.status, term_data.*, community_tags.*')
+             .where('node.status = ?', 1)
+             .where('community_tags.date > ?', (DateTime.now - 1.month).to_i)
+             .group(:name)
+             .order('count DESC')
+             .paginate(page: params[:page], per_page: 24)
+  else
+  @tags = Tag.joins(:node_tag, :node)
+             .select('node.nid, node.status, term_data.*, community_tags.*')
+             .where('node.status = ?', 1)
+             .where('community_tags.date > ?', (DateTime.now - 1.month).to_i)
+             .group(:name)
+             .order('name')
+             .paginate(page: params[:page], per_page: 24)    
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ location() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 323
+def location
+  render template: 'locations/_form'
+end
+
+ +
+ + + + +
+ + +
+ +
+ location_modal() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 327
+def location_modal
+  render template: 'locations/_modal', layout: false
+end
+
+ +
+ + + + +
+ + +
+ +
+ rss() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 267
+def rss
+  if params[:tagname][-1..-1] == '*'
+    @notes = Node.where(status: 1, type: 'note')
+                 .includes(:revision, :tag)
+                 .references(:term_data, :node_revisions)
+                 .where('term_data.name LIKE (?)', params[:tagname][0..-2] + '%')
+                 .limit(20)
+                 .order('node_revisions.timestamp DESC')
+  else
+    @notes = Tag.find_nodes_by_type([params[:tagname]], 'note', 20)
+  end
+  respond_to do |format|
+    format.rss do
+      response.headers['Content-Type'] = 'application/xml; charset=utf-8'
+      response.headers['Access-Control-Allow-Origin'] = '*'
+      render layout: false
+    end
+    format.ics do
+      response.headers['Content-Disposition'] = "attachment; filename='public-lab-events.ics'"
+      response.headers['Content-Type'] = 'text/calendar; charset=utf-8'
+      render layout: false, template: 'tag/icalendar.ics', filename: 'public-lab-events.ics'
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ show() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 43
+def show
+  # try for a matching /wiki/_TAGNAME_ or /_TAGNAME_
+  @wiki = Node.where(path: "/wiki/#{params[:id]}").try(:first) || Node.where(path: "/#{params[:id]}").try(:first)
+  default_type = if params[:id].match('question:')
+                   'questions'
+                 else
+                   'note'
+                end
+  # params[:node_type] - this is an optional param
+  # if params[:node_type] is nil - use @default_type
+  @node_type = params[:node_type] || default_type
+
+  node_type = 'note' if @node_type == 'questions' || @node_type == 'note'
+  node_type = 'page' if @node_type == 'wiki'
+  node_type = 'map' if @node_type == 'maps'
+  qids = Node.questions.where(status: 1).collect(&:nid)
+  if params[:id][-1..-1] == '*' # wildcard tags
+    @wildcard = true
+    @tags = Tag.where('name LIKE (?)', params[:id][0..-2] + '%')
+    nodes = Node.where(status: 1, type: node_type)
+                .includes(:revision, :tag)
+                .references(:term_data, :node_revisions)
+                .where('term_data.name LIKE (?) OR term_data.parent LIKE (?)', params[:id][0..-2] + '%', params[:id][0..-2] + '%')
+                .page(params[:page])
+                .order('node_revisions.timestamp DESC')
+  else
+    @tags = Tag.where(name: params[:id])
+    nodes = Node.where(status: 1, type: node_type)
+                .includes(:revision, :tag)
+                .references(:term_data, :node_revisions)
+                .where('term_data.name = ? OR term_data.parent = ?', params[:id], params[:id])
+                .page(params[:page])
+                .order('node_revisions.timestamp DESC')
+  end
+
+  # breaks the parameter
+  # sets everything to an empty array
+  set_sidebar :tags, [params[:id]]
+
+  @notes = nodes.where('node.nid NOT IN (?)', qids) if @node_type == 'note'
+  @questions = nodes.where('node.nid IN (?)', qids) if @node_type == 'questions'
+  @wikis = nodes if @node_type == 'wiki'
+  @nodes = nodes if @node_type == 'maps'
+  @title = params[:id]
+  # the following could be refactored into a Tag.contributor_count method:
+  notes = Node.where(status: 1, type: 'note')
+              .select('node.nid, node.type, node.uid, node.status, term_data.*, community_tags.*')
+              .includes(:tag)
+              .references(:term_data)
+              .where('term_data.name = ?', params[:id])
+  @length = notes.collect(&:uid).uniq.length || 0
+
+  respond_with(nodes) do |format|
+    format.html { render 'tag/show' }
+    format.xml  { render xml: nodes }
+    format.json do
+      json = []
+      nodes.each do |node|
+        json << node.as_json(except: %[path tags])
+        json.last['path'] = 'https://' + request.host.to_s + node.path
+        json.last['preview'] = node.body_preview(500)
+        json.last['image'] = node.main_image.path(:large) if node.main_image
+        json.last['tags'] = Node.find(node.id).tags.collect(&:name) if node.tags
+      end
+      render json: json
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ show_for_author() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 112
+def show_for_author
+  if params[:id][-1..-1] == '*' # wildcard tags
+    @wildcard = true
+    @tags = Tag.where('name LIKE (?)', params[:id][0..-2] + '%')
+  else
+    @tags = Tag.where(name: params[:id])
+  end
+  @tagname = params[:id]
+  @user = User.find_by(name: params[:author])
+  @title = "'" + @tagname.to_s + "' by " +  params[:author]
+  @notes = Tag.tagged_nodes_by_author(@tagname, @user)
+  @unpaginated = true
+  @node_type = 'note'
+  @wiki = nil
+  respond_with(@notes) do |format|
+    format.html { render 'tag/show' }
+    format.xml  { render xml: @notes }
+    format.json do
+      json = []
+      @notes.each do |node|
+        json << node.as_json(except: %[path tags])
+        json.last['path'] = 'https://' + request.host.to_s + node.path
+        json.last['preview'] = node.body_preview(500)
+        json.last['image'] = node.main_image.path(:large) if node.main_image
+        json.last['tags'] = Node.find(node.id).tags.collect(&:name) if node.tags
+      end
+      render json: json
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ suggested() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 250
+def suggested
+  if params[:id].length > 2
+    @suggestions = []
+    # filtering out tag spam by requiring tags attached to a published node
+    Tag.where('name LIKE ?', '%' + params[:id] + '%')
+       .includes(:node)
+       .references(:node)
+       .where('node.status = 1')
+       .limit(10).each do |tag|
+      @suggestions << tag.name.downcase
+    end
+    render json: @suggestions.uniq
+  else
+    render json: []
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ widget() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/tag_controller.rb, line 143
+def widget
+  num = params[:n] || 4
+  nids = Tag.find_nodes_by_type(params[:id], 'note', num).collect(&:nid)
+  @notes = Node.page(params[:page])
+               .where('status = 1 AND nid in (?)', nids)
+               .order('nid DESC')
+  render layout: false
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/TagHelper.html b/doc/app/TagHelper.html new file mode 100644 index 0000000000..19924381e3 --- /dev/null +++ b/doc/app/TagHelper.html @@ -0,0 +1,95 @@ + + + + + + +module TagHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module TagHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/TagList.html b/doc/app/TagList.html new file mode 100644 index 0000000000..48bf339318 --- /dev/null +++ b/doc/app/TagList.html @@ -0,0 +1,338 @@ + + + + + + +class TagList - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class TagList +

+ +
+ +

List of tag values from a search

+ +
+ + + + +
+ + + + + + + +
+
+

Attributes

+
+ + +
+
+ items[RW] +
+ +
+ + + +
+
+ +
+
+ srchParams[RW] +
+ +
+ + + +
+
+ +
+ + + +
+
+

Public Class Methods

+
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_list.rb, line 5
+def initialize; end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ addAll(tlist) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_list.rb, line 16
+def addAll(tlist)
+  @items ||= []
+  tlist.each { |tItem| @items << tItem } unless tlist.nil?
+end
+
+ +
+ + + + +
+ + +
+ +
+ addTag(ntag) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_list.rb, line 11
+def addTag(ntag)
+  @items ||= []
+  @items << ntag
+end
+
+ +
+ + + + +
+ + +
+ +
+ getTags() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_list.rb, line 21
+def getTags
+  @item ||= []
+  @items
+end
+
+ +
+ + + + +
+ + +
+ +
+ setSrchParams=(value) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_list.rb, line 7
+def setSrchParams=(value)
+  @srchParams = value
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/TagList/Entity.html b/doc/app/TagList/Entity.html new file mode 100644 index 0000000000..ae6d0fd9a5 --- /dev/null +++ b/doc/app/TagList/Entity.html @@ -0,0 +1,107 @@ + + + + + + +class TagList::Entity - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class TagList::Entity +

+ +
+ +

This subclass is used to auto-generate the RESTful data structure. It is +generally not useful for internal Ruby usage

+ +
but must be included for full RESTful functionality.
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/TagList/Entity/TagResult.html b/doc/app/TagList/Entity/TagResult.html new file mode 100644 index 0000000000..7101af3990 --- /dev/null +++ b/doc/app/TagList/Entity/TagResult.html @@ -0,0 +1,95 @@ + + + + + + +module TagList::Entity::TagResult - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module TagList::Entity::TagResult +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/TagResult.html b/doc/app/TagResult.html new file mode 100644 index 0000000000..5a27204e75 --- /dev/null +++ b/doc/app/TagResult.html @@ -0,0 +1,253 @@ + + + + + + +class TagResult - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class TagResult +

+ +
+ +

Tags are text values assigned to various site documents.

+ +
+ + + + +
+ + + + + + + +
+
+

Attributes

+
+ + +
+
+ tagId[RW] +
+ +
+ + + +
+
+ +
+
+ tagSource[RW] +
+ +
+ + + +
+
+ +
+
+ tagType[RW] +
+ +
+ + + +
+
+ +
+
+ tagVal[RW] +
+ +
+ + + +
+
+ +
+ + + +
+
+

Public Class Methods

+
+ + +
+ +
+ fromSearch(tid, tval, ttype, tsrc) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_result.rb, line 7
+def self.fromSearch(tid, tval, ttype, tsrc)
+  obj = new
+  obj.tagId =     tid
+  obj.tagVal =    tval
+  obj.tagType =   ttype
+  obj.tagSource = tsrc
+  obj
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_result.rb, line 5
+def initialize; end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/TagResult/Entity.html b/doc/app/TagResult/Entity.html new file mode 100644 index 0000000000..1d526d94dd --- /dev/null +++ b/doc/app/TagResult/Entity.html @@ -0,0 +1,107 @@ + + + + + + +class TagResult::Entity - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class TagResult::Entity +

+ +
+ +

This subclass is used to auto-generate the RESTful data structure. It is +generally not useful for internal Ruby usage

+ +
but must be included for full RESTful functionality.
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/TagSelection.html b/doc/app/TagSelection.html new file mode 100644 index 0000000000..6db971535c --- /dev/null +++ b/doc/app/TagSelection.html @@ -0,0 +1,223 @@ + + + + + + +class TagSelection - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class TagSelection +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ ruser() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_selection.rb, line 15
+def ruser
+  User.find_by(id: user_id)
+end
+
+ +
+ + + + +
+ + +
+ +
+ tagname() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_selection.rb, line 19
+def tagname
+  tag.name
+end
+
+ +
+ + + + +
+ + +
+ +
+ user() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/tag_selection.rb, line 11
+def user
+  DrupalUser.find_by(uid: user_id)
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/TalkController.html b/doc/app/TalkController.html new file mode 100644 index 0000000000..eca3f01c4f --- /dev/null +++ b/doc/app/TalkController.html @@ -0,0 +1,154 @@ + + + + + + +class TalkController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class TalkController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ show() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/talk_controller.rb, line 2
+def show
+  @node = Node.find_by_path params[:id]
+  @node = Node.find_by_path 'wiki/' + params[:id] if @node.nil?
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/TypeaheadService.html b/doc/app/TypeaheadService.html new file mode 100644 index 0000000000..b06d0a9ae3 --- /dev/null +++ b/doc/app/TypeaheadService.html @@ -0,0 +1,777 @@ + + + + + + +class TypeaheadService - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class TypeaheadService +

+ +
+ +

The TypeaheadService class is a utility +class whose purpose is to provide fast responses to text queries within +different categories (record types, functionality, subsystems, etc). Though +similar in operation to the SearchService, +the implementation is separate, in that the goal of the response is to +provide fast returns at a higher level than a general search. In +effect, TypeaheadService provides +pointers to better searches, while SearchService provides deep and detailed +information. TODO: Refactor TypeaheadService and SearchService so that common functions come +from a higher level class?

+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/typeahead_service.rb, line 8
+def initialize; end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ comments(input, limit = 5) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/typeahead_service.rb, line 35
+def comments(input, limit = 5)
+  if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
+    Comment.search(input)
+           .limit(limit)
+           .order('nid DESC')
+           .where(status: 1)
+  else 
+    Comment.limit(limit)
+           .order('nid DESC')
+           .where('status = 1 AND comment LIKE ?', '%' + input + '%')
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ maps(input, limit = 5) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/typeahead_service.rb, line 80
+def maps(input, limit = 5)
+  Node.limit(limit)
+      .order('nid DESC')
+      .where('type = "map" AND node.status = 1 AND title LIKE ?', '%' + input + '%')
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes(input, limit = 5) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/typeahead_service.rb, line 48
+def notes(input, limit = 5)
+  if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
+    Node.search(input)
+        .group(:nid)
+        .includes(:node)
+        .references(:node)
+        .limit(limit)
+        .where("node.type": "note", "node.status": 1)
+        .order(timestamp: :desc)
+  else 
+    Node.limit(limit)
+        .group(:nid)
+        .where(type: "note", status: 1)
+        .order(updated_at: :desc)
+        .where('title LIKE ?', '%' + input + '%')
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ search_all(srchString, limit = 5) + + click to toggle source + +
+ + +
+ +

Run a search in any of the associated systems for references that contain +the search string

+ + + + +
+
# File app/services/typeahead_service.rb, line 87
+def search_all(srchString, limit = 5)
+  sresult = TagList.new
+  unless srchString.nil? || srchString == 0
+    # notes
+    notesrch = search_notes(srchString, limit)
+    sresult.addAll(notesrch.getTags)
+    # wikis
+    wikisrch = search_wikis(srchString, limit)
+    sresult.addAll(wikisrch.getTags)
+    # User profiles
+    usersrch = search_profiles(srchString, limit)
+    sresult.addAll(usersrch.getTags)
+    # Tags -- handled differently because tag
+    tagsrch = search_tags(srchString, limit)
+    sresult.addAll(tagsrch.getTags)
+    # maps
+    mapsrch = search_maps(srchString, limit)
+    sresult.addAll(mapsrch.getTags)
+    # questions
+    qsrch = search_questions(srchString, limit)
+    sresult.addAll(qsrch.getTags)
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ search_maps(srchString, limit = 5) + + click to toggle source + +
+ + +
+ +

Search maps for matching text

+ + + + +
+
# File app/services/typeahead_service.rb, line 162
+def search_maps(srchString, limit = 5)
+  sresult = TagList.new
+  unless srchString.nil? || srchString == 0
+    # maps
+    maps(srchString, limit).select('title,type,nid,path').each do |match|
+      tval = TagResult.new
+      tval.tagId = match.nid
+      tval.tagVal = match.title
+      tval.tagType = match.icon
+      tval.tagSource = match.path
+      sresult.addTag(tval)
+    end
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ search_notes(srchString, limit = 5) + + click to toggle source + +
+ + +
+ +

Search notes for matching strings

+ + + + +
+
# File app/services/typeahead_service.rb, line 130
+def search_notes(srchString, limit = 5)
+  sresult = TagList.new
+  unless srchString.nil? || srchString == 0
+    notes(srchString, limit).uniq.each do |match|
+      tval = TagResult.new
+      tval.tagId = match.nid
+      tval.tagVal = match.title
+      tval.tagType = 'file'
+      tval.tagSource = match.path
+      sresult.addTag(tval)
+    end
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ search_profiles(srchString, limit = 5) + + click to toggle source + +
+ + +
+ +

Search profiles for matching text

+ + + + +
+
# File app/services/typeahead_service.rb, line 113
+def search_profiles(srchString, limit = 5)
+  sresult = TagList.new
+  unless srchString.nil? || srchString == 0
+    # User profiles
+    users(srchString, limit).each do |match|
+      tval = TagResult.new
+      tval.tagId = 0
+      tval.tagType = 'user'
+      tval.tagVal = match.username
+      tval.tagSource = '/profile/' + match.username
+      sresult.addTag(tval)
+    end
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ search_questions(srchString, limit = 5) + + click to toggle source + +
+ + +
+ +

Search question entries for matching text

+ + + + +
+
# File app/services/typeahead_service.rb, line 196
+def search_questions(srchString, limit = 5)
+  sresult = TagList.new
+  questions = Node.where(
+    'type = "note" AND node.status = 1 AND title LIKE ?',
+    '%' + srchString + '%'
+  )
+                  .joins(:tag)
+                  .where('term_data.name LIKE ?', 'question:%')
+                  .order('node.nid DESC')
+                  .limit(limit)
+  questions.each do |match|
+    tval = TagResult.fromSearch(
+      match.nid,
+      match.title,
+      'question-circle',
+      match.path
+    )
+    sresult.addTag(tval)
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ search_tags(srchString, limit = 5) + + click to toggle source + +
+ + +
+ +

Search tag values for matching text

+ + + + +
+
# File app/services/typeahead_service.rb, line 179
+def search_tags(srchString, limit = 5)
+  sresult = TagList.new
+  unless srchString.nil? || srchString == 0
+    # Tags
+    tlist = tags(srchString, limit)
+    tlist.each do |match|
+      ntag = TagResult.new
+      ntag.tagId = 0
+      ntag.tagVal = match.name
+      ntag.tagType = 'tag'
+      sresult.addTag(ntag)
+    end
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ search_wikis(srchString, limit = 5) + + click to toggle source + +
+ + +
+ +

Search wikis for matching strings

+ + + + +
+
# File app/services/typeahead_service.rb, line 146
+def search_wikis(srchString, limit = 5)
+  sresult = TagList.new
+  unless srchString.nil? || srchString == 0
+    wikis(srchString, limit).select('node.title,node.type,node.nid,node.path').each do |match|
+      tval = TagResult.new
+      tval.tagId = match.nid
+      tval.tagVal = match.title
+      tval.tagType = 'file'
+      tval.tagSource = match.path
+      sresult.addTag(tval)
+    end
+  end
+  sresult
+end
+
+ +
+ + + + +
+ + +
+ +
+ tags(input, limit = 5) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/typeahead_service.rb, line 27
+def tags(input, limit = 5)
+  Tag.includes(:node)
+     .references(:node)
+     .where('node.status = 1')
+     .limit(limit)
+     .where('name LIKE ?', '%' + input + '%')
+end
+
+ +
+ + + + +
+ + +
+ +
+ users(input, limit = 5) + + click to toggle source + +
+ + +
+ +

search_users() returns a standard TagResult; +users() returns an array of User records It's +unclear if TagResult was supposed to be broken +into other types like DocResult? but perhaps +could simply be renamed Result.

+ + + + +
+
# File app/services/typeahead_service.rb, line 15
+def users(input, limit = 5)
+  if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
+    User.search(input)
+        .limit(limit)
+        .where(status: 1)
+  else 
+    User.limit(limit)
+        .order('id DESC')
+        .where('username LIKE ? AND status = 1', '%' + input + '%')
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ wikis(input, limit = 5) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/services/typeahead_service.rb, line 66
+def wikis(input, limit = 5)
+  if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
+    Node.search(input)
+        .includes(:node)
+        .references(:node)
+        .limit(limit)
+        .where("node.type": "page", "node.status": 1)
+  else 
+    Node.limit(limit)
+        .order('nid DESC')
+        .where('type = "page" AND node.status = 1 AND title LIKE ?', '%' + input + '%')
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/UniqueUrlValidator.html b/doc/app/UniqueUrlValidator.html new file mode 100644 index 0000000000..39428e974c --- /dev/null +++ b/doc/app/UniqueUrlValidator.html @@ -0,0 +1,162 @@ + + + + + + +class UniqueUrlValidator - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class UniqueUrlValidator +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ validate(record) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/node.rb, line 2
+def validate(record)
+  if record.title == '' || record.title.nil?
+    # record.errors[:base] << "You must provide a title."
+    # otherwise the below title uniqueness check fails, as title presence validation doesn't run until after
+  elsif record.title == 'new' && record.type == 'page'
+    record.errors[:base] << "You may not use the title 'new'." # otherwise the below title uniqueness check fails, as title presence validation doesn't run until after
+  else
+    if !Node.where(path: record.generate_path).first.nil? && record.type == 'note'
+      record.errors[:base] << 'You have already used this title today.'
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/UniqueUsernameValidator.html b/doc/app/UniqueUsernameValidator.html new file mode 100644 index 0000000000..cd547d83ac --- /dev/null +++ b/doc/app/UniqueUsernameValidator.html @@ -0,0 +1,155 @@ + + + + + + +class UniqueUsernameValidator - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class UniqueUsernameValidator +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ validate(record) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 2
+def validate(record)
+  if DrupalUser.find_by(name: record.username) && record.openid_identifier.nil?
+    record.errors[:base] << 'That username is already taken. If this is your username, you can simply log in to this site.'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/User.html b/doc/app/User.html new file mode 100644 index 0000000000..82b8775a05 --- /dev/null +++ b/doc/app/User.html @@ -0,0 +1,1585 @@ + + + + + + +class User - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class User +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + + + + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ add_to_lists(lists) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 181
+def add_to_lists(lists)
+  lists.each do |list|
+    WelcomeMailer.add_to_list(self, list)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ barnstars() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 274
+def barnstars
+  NodeTag.includes(:node, :tag)
+         .references(:term_data)
+         .where('type = ? AND term_data.name LIKE ? AND node.uid = ?', 'note', 'barnstar:%', uid)
+end
+
+ +
+ + + + +
+ + +
+ +
+ coauthored_notes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 97
+def coauthored_notes
+  coauthored_tag = "with:" + self.name.downcase
+  Node.where(status: 1, type: "note")
+      .includes(:revision, :tag)
+      .references(:term_data, :node_revisions)
+      .where('term_data.name = ? OR term_data.parent = ?', coauthored_tag.to_s , coauthored_tag.to_s)
+end
+
+ +
+ + + + +
+ + +
+ +
+ comment_streak(span = 365) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 248
+def comment_streak(span = 365)
+  days = {}
+  streak = 0
+  comment_count = 0
+  (0..span).each do |day|
+    days[day] = Comment.select(:timestamp)
+                       .where( uid: drupal_user.uid,
+                               status: 1,
+                               timestamp: Time.now.midnight.to_i - day.days.to_i..Time.now.midnight.to_i - (day - 1).days.to_i)
+                       .count
+    break if days[day] == 0
+    streak += 1
+    comment_count += days[day]
+  end
+  [streak, comment_count]
+end
+
+ +
+ + + + +
+ + +
+ +
+ content_followed_in_past_period(time_period) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 313
+def content_followed_in_past_period(time_period)
+  self.node.where("created >= #{time_period.to_i}  AND changed >= #{time_period.to_i}")
+end
+
+ +
+ + + + +
+ + +
+ +
+ create_drupal_user() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 47
+def create_drupal_user
+  self.bio ||= ''
+  if drupal_user.nil?
+          drupal_user = DrupalUser.new(name: username,
+                                  pass: rand(100_000_000_000_000_000_000),
+                                  mail: email,
+                                  mode: 0,
+                                  sort: 0,
+                                  threshold: 0,
+                                  theme: '',
+                                  signature: '',
+                                  signature_format: 0,
+                                  created: DateTime.now.to_i,
+                                  access: DateTime.now.to_i,
+                                  login: DateTime.now.to_i,
+                                  status: 1,
+                                  timezone: nil,
+                                  language: '',
+                                  picture: '',
+                                  init: '',
+                                  data: nil,
+                                  timezone_id: 0,
+                                  timezone_name: '')
+    drupal_user.save!
+    self.id = drupal_user.uid
+  else
+    self.id = DrupalUser.find_by(name: username).uid
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ destroy_drupal_user() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 77
+def destroy_drupal_user
+  drupal_user.destroy
+end
+
+ +
+ + + + +
+ + +
+ +
+ drupal_user() + + click to toggle source + +
+ + +
+ +

this is ridiculous. We need to store uid in this model. …migration is in +progress. start getting rid of these calls…

+ + + + +
+
# File app/models/user.rb, line 87
+def drupal_user
+  DrupalUser.find_by(name: username)
+end
+
+ +
+ + + + +
+ + +
+ +
+ first_time_poster() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 284
+def first_time_poster
+  notes.where(status: 1).count == 0
+end
+
+ +
+ + + + +
+ + +
+ +
+ follow(other_user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 288
+def follow(other_user)
+  active_relationships.create(followed_id: other_user.id)
+end
+
+ +
+ + + + +
+ + +
+ +
+ following(tagname) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 176
+def following(tagname)
+  tids = Tag.where(name: tagname).collect(&:tid)
+  !TagSelection.where(following: true, tid: tids, user_id: uid).empty?
+end
+
+ +
+ + + + +
+ + +
+ +
+ following?(other_user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 296
+def following?(other_user)
+  following_users.include?(other_user)
+end
+
+ +
+ + + + +
+ + +
+ +
+ generate_reset_key() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 105
+def generate_reset_key
+  # invent a key and save it
+  key = ''
+  20.times do
+    key += [*'a'..'z'].sample
+  end
+  self.reset_key = key
+  key
+end
+
+ +
+ + + + +
+ + +
+ +
+ get_value_of_power_tag(key) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 163
+def get_value_of_power_tag(key)
+  tname = self.user_tags.where('value LIKE ?' , key + ':%')
+  tvalue = tname.first.name.partition(':').last
+  tvalue
+end
+
+ +
+ + + + +
+ + +
+ +
+ has_power_tag(key) + + click to toggle source + +
+ + +
+ +

power tags have “key:value” format, and should be searched with a “key:*” +wildcard

+ + + + +
+
# File app/models/user.rb, line 158
+def has_power_tag(key)
+   tids = self.user_tags.where('value LIKE ?' , key + ':%').collect(&:id)
+   !tids.blank?
+end
+
+ +
+ + + + +
+ + +
+ +
+ has_role(r) + + click to toggle source + +
+ + +
+ +

we can revise/improve this for m2m later…

+ + + + +
+
# File app/models/user.rb, line 136
+def has_role(r)
+  role == r
+end
+
+ +
+ + + + +
+ + +
+ +
+ has_tag(tagname) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 153
+def has_tag(tagname)
+  user_tags.collect(&:value).include?(tagname)
+end
+
+ +
+ + + + +
+ + +
+ +
+ lat() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 127
+def lat
+  drupal_user.lat
+end
+
+ +
+ + + + +
+ + +
+ +
+ lon() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 131
+def lon
+  drupal_user.lon
+end
+
+ +
+ + + + +
+ + +
+ +
+ note_streak(span = 365) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 212
+def note_streak(span = 365)
+  days = {}
+  streak = 0
+  note_count = 0
+  (0..span).each do |day|
+    days[day] = Node.select(:created)
+                    .where( uid: drupal_user.uid,
+                            type: 'note',
+                            status: 1,
+                            created: Time.now.midnight.to_i - day.days.to_i..Time.now.midnight.to_i - (day - 1).days.to_i)
+                    .count
+    break if days[day] == 0
+    streak += 1
+    note_count += days[day]
+  end
+  [streak, note_count]
+end
+
+ +
+ + + + +
+ + +
+ +
+ notes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 91
+def notes
+  Node.where(uid: uid)
+      .where(type: 'note')
+      .order('created DESC')
+end
+
+ +
+ + + + +
+ + +
+ +
+ path() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 123
+def path
+  "/profile/#{self.username}"
+end
+
+ +
+ + + + +
+ + +
+ +
+ photo_path(size = :medium) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 280
+def photo_path(size = :medium)
+  photo.url(size)
+end
+
+ +
+ + + + +
+ + +
+ +
+ profile_image() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 300
+def profile_image
+  if photo_file_name
+    puts photo_path(:thumb)
+    photo_path(:thumb)
+  else
+    "https://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(email)}"
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ questions() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 309
+def questions
+  Node.questions.where(status: 1, uid: id)
+end
+
+ +
+ + + + +
+ + +
+ +
+ set_token() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 81
+def set_token
+  self.token = SecureRandom.uuid if self.token.nil?
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+ streak(span = 365) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 265
+def streak(span = 365)
+  note_streak = self.note_streak(span)
+  wiki_edit_streak = self.wiki_edit_streak(span)
+  comment_streak = self.comment_streak(span)
+  streak_count = [note_streak[1], wiki_edit_streak[1], comment_streak[1]]
+  streak = [note_streak[0], wiki_edit_streak[0], comment_streak[0]]
+  [streak.max, streak_count]
+end
+
+ +
+ + + + +
+ + +
+ +
+ subscriptions(type = :tag) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 169
+def subscriptions(type = :tag)
+  if type == :tag
+    TagSelection.where(user_id: uid,
+                       following: true)
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ tagnames(limit = 20, defaults = true) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 144
+def tagnames(limit = 20, defaults = true)
+  tagnames = []
+  Node.order('nid DESC').where(type: 'note', status: 1, uid: self.id).limit(limit).each do |node|
+    tagnames += node.tags.collect(&:name)
+  end
+  tagnames += ['balloon-mapping', 'spectrometer', 'near-infrared-camera', 'thermal-photography', 'newsletter'] if tagnames.empty? && defaults
+  tagnames.uniq
+end
+
+ +
+ + + + +
+ + +
+ +
+ tags(limit = 10) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 140
+def tags(limit = 10)
+  Tag.where('name in (?)', tagnames).limit(limit)
+end
+
+ +
+ + + + +
+ + +
+ +
+ title() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 119
+def title
+  self.username
+end
+
+ +
+ + + + +
+ + +
+ +
+ uid() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 115
+def uid
+  drupal_user.uid
+end
+
+ +
+ + + + +
+ + +
+ +
+ unfollow(other_user) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 292
+def unfollow(other_user)
+  active_relationships.where(followed_id: other_user.id).first.destroy
+end
+
+ +
+ + + + +
+ + +
+ +
+ weekly_comment_tally(span = 52) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 200
+def weekly_comment_tally(span = 52)
+  weeks = {}
+  (0..span).each do |week|
+    weeks[span - week] = Comment.select(:timestamp)
+                                .where( uid: drupal_user.uid,
+                                        status: 1,
+                                        timestamp: Time.now.to_i - week.weeks.to_i..Time.now.to_i - (week - 1).weeks.to_i)
+                                .count
+  end
+  weeks
+end
+
+ +
+ + + + +
+ + +
+ +
+ weekly_note_tally(span = 52) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 187
+def weekly_note_tally(span = 52)
+  weeks = {}
+  (0..span).each do |week|
+    weeks[span - week] = Node.select(:created)
+                             .where( uid: drupal_user.uid,
+                                     type: 'note',
+                                     status: 1,
+                                     created: Time.now.to_i - week.weeks.to_i..Time.now.to_i - (week - 1).weeks.to_i)
+                             .count
+  end
+  weeks
+end
+
+ +
+ + + + +
+ + +
+ +
+ wiki_edit_streak(span = 365) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user.rb, line 230
+def wiki_edit_streak(span = 365)
+  days = {}
+  streak = 0
+  wiki_edit_count = 0
+  (0..span).each do |day|
+    days[day] = Revision.joins(:node)
+                        .where( uid: drupal_user.uid,
+                                status: 1,
+                                timestamp: Time.now.midnight.to_i - day.days.to_i..Time.now.midnight.to_i - (day - 1).days.to_i)
+                        .where('node.type != ?', 'note')
+                        .count
+    break if days[day] == 0
+    streak += 1
+    wiki_edit_count += days[day]
+  end
+  [streak, wiki_edit_count]
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/User/Authlogic.html b/doc/app/User/Authlogic.html new file mode 100644 index 0000000000..c55605c438 --- /dev/null +++ b/doc/app/User/Authlogic.html @@ -0,0 +1,95 @@ + + + + + + +module User::Authlogic - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module User::Authlogic +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/User/Authlogic/CryptoProviders.html b/doc/app/User/Authlogic/CryptoProviders.html new file mode 100644 index 0000000000..90e5df85dd --- /dev/null +++ b/doc/app/User/Authlogic/CryptoProviders.html @@ -0,0 +1,95 @@ + + + + + + +module User::Authlogic::CryptoProviders - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module User::Authlogic::CryptoProviders +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/UserSelection.html b/doc/app/UserSelection.html new file mode 100644 index 0000000000..e26e92fe2e --- /dev/null +++ b/doc/app/UserSelection.html @@ -0,0 +1,102 @@ + + + + + + +class UserSelection - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class UserSelection +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/UserSession.html b/doc/app/UserSession.html new file mode 100644 index 0000000000..0c3321d4da --- /dev/null +++ b/doc/app/UserSession.html @@ -0,0 +1,102 @@ + + + + + + +class UserSession - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class UserSession +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/UserSessionsController.html b/doc/app/UserSessionsController.html new file mode 100644 index 0000000000..856653f1c5 --- /dev/null +++ b/doc/app/UserSessionsController.html @@ -0,0 +1,325 @@ + + + + + + +class UserSessionsController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class UserSessionsController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/user_sessions_controller.rb, line 6
+def create
+  params[:user_session][:username] = params[:openid] if params[:openid] # second runthrough must preserve username
+  username = params[:user_session][:username] if params[:user_session]
+  @user = User.find_by(username: username)
+
+  # try finding by email, if that exists
+  if @user.nil? && !User.where(email: username).empty?
+    @user = User.find_by(email: username)
+    params[:user_session][:username] = @user.username
+  end
+
+  if params[:user_session].nil? || @user && @user.drupal_user.status == 1 || @user.nil?
+    # an existing native user
+    if params[:user_session].nil? || @user
+      if @user && @user.crypted_password.nil? # the user has not created a pwd in the new site
+        params[:user_session][:openid_identifier] = 'https://old.publiclab.org/people/' + username + '/identity' if username
+        params[:user_session].delete(:password)
+        params[:user_session].delete(:username)
+        params[:openid] = username # pack up username for second runthrough
+      end
+      @user_session = UserSession.new(params[:user_session])
+      saved = @user_session.save do |result|
+        if result
+          # replace this with temporarily saving pwd in session,
+          # and automatically saving it in the user record after login is completed
+          if current_user.crypted_password.nil? # the user has not created a pwd in the new site
+            flash[:warning] = I18n.t('user_sessions_controller.create_password_for_new_site')
+            redirect_to '/profile/edit'
+          else
+            flash[:notice] = I18n.t('user_sessions_controller.logged_in')
+            if session[:openid_return_to] # for openid login, redirects back to openid auth process
+              return_to = session[:openid_return_to]
+              session[:openid_return_to] = nil
+              redirect_to return_to
+            elsif session[:return_to]
+              return_to = session[:return_to]
+              session[:return_to] = nil
+              redirect_to return_to
+            elsif params[:return_to]
+              redirect_to params[:return_to]
+            else
+              redirect_to '/dashboard'
+            end
+          end
+        else
+          render action: 'new'
+        end
+      end
+    else # not a native user
+      if !DrupalUser.find_by(name: username).nil?
+        # this is a user from the old site who hasn't registered on the new site
+        redirect_to controller: :users, action: :create, user: { openid_identifier: username }
+      else # totally new user!
+        flash[:warning] = I18n.t('user_sessions_controller.sign_up_to_join')
+        redirect_to '/signup'
+      end
+    end
+  elsif params[:user_session].nil? || @user && @user.drupal_user.status == 5 || @user.nil?
+    flash[:error] = I18n.t('user_sessions_controller.user_has_been_moderated', username: @user.username).html_safe
+    redirect_to '/'
+  else
+    flash[:error] = I18n.t('user_sessions_controller.user_has_been_banned', username: @user.username).html_safe
+    redirect_to '/'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ destroy() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/user_sessions_controller.rb, line 72
+def destroy
+  @user_session = UserSession.find
+  @user_session.destroy
+  flash[:notice] = I18n.t('user_sessions_controller.logged_out')
+  redirect_to '/' + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ logout_remotely() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/user_sessions_controller.rb, line 79
+def logout_remotely
+  current_user.reset_persistence_token!
+  flash[:notice] = I18n.t('user_sessions_controller.logged_out')
+  redirect_to '/' + '?_=' + Time.now.to_i.to_s
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/user_sessions_controller.rb, line 2
+def new
+  @title = I18n.t('user_sessions_controller.log_in')
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/UserTag.html b/doc/app/UserTag.html new file mode 100644 index 0000000000..a3a009e629 --- /dev/null +++ b/doc/app/UserTag.html @@ -0,0 +1,231 @@ + + + + + + +class UserTag - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class UserTag +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Class Methods

+
+ + +
+ +
+ exists?(uid, value) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user_tag.rb, line 14
+def self.exists?(uid, value)
+  UserTag.where(uid: uid, value: value).count > 0
+end
+
+ +
+ + + + +
+ + +
+ +
+
+

Public Instance Methods

+
+ + +
+ +
+ name() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user_tag.rb, line 18
+def name
+  self.value
+end
+
+ +
+ + + + +
+ + +
+ +
+ preprocess() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/models/user_tag.rb, line 10
+def preprocess
+  self.value = self.value.downcase
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/UserTagsController.html b/doc/app/UserTagsController.html new file mode 100644 index 0000000000..bf5ca5dbda --- /dev/null +++ b/doc/app/UserTagsController.html @@ -0,0 +1,319 @@ + + + + + + +class UserTagsController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class UserTagsController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/user_tags_controller.rb, line 4
+def create
+
+  @output = {
+    errors: [],
+    saved: []
+  }
+  exist = false
+
+  user = User.find(params[:id])
+
+  if current_user && (current_user.role == 'admin' || current_user == user)
+    if params[:name]
+      tagnames = params[:name].split(',')
+      tagnames.each do |tagname|
+        name = tagname.downcase
+        if UserTag.exists?(current_user.id, name)
+          @output[:errors] << I18n.t('user_tags_controller.tag_already_exists')
+          exist = true
+        end
+ 
+        unless exist
+          user_tag = user.user_tags.build(value: name)
+          if user_tag.save
+            @output[:saved] << [name, user_tag.id]
+          else
+            @output[:errors] << I18n.t('user_tags_controller.cannot_save_value')
+          end
+        end
+      end
+    else
+      @output[:errors] << I18n.t('user_tags_controller.value_cannot_be_empty')
+    end
+  else
+    @output[:errors] << I18n.t('user_tags_controller.admin_user_manage_tags')
+  end
+
+  if request.xhr?
+    render json: @output
+  else
+    if !@output[:errors].empty?
+      flash[:error] = I18n.t('user_tags_controller.errors_occured', count: @output[:errors].length).html_safe
+    else
+      flash[:notice] = I18n.t('user_tags_controller.tag_created', tag_name: @output[:saved][0][0]).html_safe
+    end
+    redirect_to info_path, id: params[:id]
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/user_tags_controller.rb, line 52
+def delete
+  output = {
+    status: false,
+    errors: []
+  }
+  message = ''
+
+  begin  
+    @user_tag = UserTag.where(uid: params[:id], value: params[:name])
+    if(!@user_tag.nil?)
+        @user_tag = @user_tag.first 
+    end 
+
+    if current_user.role == 'admin' || params[:id].to_i == current_user.id
+      if (!@user_tag.nil? && @user_tag.user == current_user) || (!@user_tag.nil? && current_user.role == 'admin')
+        UserTag.where(uid: params[:id] , value: params[:name]).destroy_all    
+        message = I18n.t('user_tags_controller.tag_deleted')
+        output[:status] = true
+      else
+        output[:status] = false
+        message = I18n.t('user_tags_controller.tag_doesnt_exist')
+      end
+    else
+      message = I18n.t('user_tags_controller.admin_user_manage_tags')
+    end
+  rescue ActiveRecord::RecordNotFound
+    output[:status] = false
+    message = I18n.t('user_tags_controller.tag_doesnt_exist')
+  end
+
+  output[:errors] << message
+  respond_with do |format|
+    format.js
+    format.html do
+      if request.xhr?
+        render json: output
+      else
+        if output[:status]
+          flash[:notice] = message
+        else
+          flash[:error] = message
+        end
+        redirect_to info_path
+      end
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ suggested() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/user_tags_controller.rb, line 100
+def suggested
+  if !params[:name].empty?
+    suggested = []
+    UserTag.where('value LIKE ?', params[:name] + '%').each do |tag|
+      suggested << tag.value
+    end
+    render json: suggested.uniq
+  else
+    render json: []
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/UserTagsHelper.html b/doc/app/UserTagsHelper.html new file mode 100644 index 0000000000..93db2d268f --- /dev/null +++ b/doc/app/UserTagsHelper.html @@ -0,0 +1,151 @@ + + + + + + +module UserTagsHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module UserTagsHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ fetch_tags(uid, type) + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/helpers/user_tags_helper.rb, line 2
+def fetch_tags(uid, type)
+  tag_types = %w[skill gear role tool]
+  tags = []
+  if tag_types.include? type
+    tags = UserTag.where(uid: uid).where('value LIKE ?', type + ':' + '%')
+  end
+  tags
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/UsersController.html b/doc/app/UsersController.html new file mode 100644 index 0000000000..4d16368690 --- /dev/null +++ b/doc/app/UsersController.html @@ -0,0 +1,815 @@ + + + + + + +class UsersController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class UsersController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ comments() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 221
+def comments
+  @comments = Comment.limit(20)
+                           .order("timestamp DESC")
+                           .where(status: 0, uid: params[:id])
+                           .paginate(page: params[:page])
+  render partial: 'comments/comments'
+end
+
+ +
+ + + + +
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 11
+def create
+  @user = User.new(params[:user])
+  using_recaptcha = !params[:spamaway] && Rails.env == "production"
+  recaptcha = verify_recaptcha(model: @user) if using_recaptcha
+  @spamaway = Spamaway.new(params[:spamaway]) unless using_recaptcha
+  if ((@spamaway && @spamaway.valid?) || recaptcha) && @user.save({})
+    if current_user.crypted_password.nil? # the user has not created a pwd in the new site
+      flash[:warning] = I18n.t('users_controller.account_migrated_create_new_password')
+      redirect_to "/profile/edit"
+    else
+      @user.add_to_lists(['publiclaboratory'])
+      flash[:notice] = I18n.t('users_controller.registration_successful').html_safe
+      flash[:warning] = I18n.t('users_controller.spectralworkbench_or_mapknitter', :url1 => "'#{session[:openid_return_to]}'").html_safe if session[:openid_return_to]
+      session[:openid_return_to] = nil
+      redirect_to "/dashboard"
+    end
+  else
+    # pipe all spamaway errors into the user error display
+    if @spamaway
+      @spamaway.errors.full_messages.each do |message|
+        @user.errors.add(:spam_detection, message)
+      end
+    elsif using_recaptcha && recaptcha == false
+      flash.now[:warning] = "If you're having trouble creating an account, try <a href='/signup?spamaway=true'>the alternative signup form</a>, or <a href='mailto:staff@publiclab.org'>ask staff for help</a>"
+    end
+    # send all errors to the page so the user can try again
+    @action = "create"
+    render action: 'new'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ edit() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 66
+def edit
+  @action = "update" # sets the form url
+  if params[:id] # admin only
+    @drupal_user = DrupalUser.find_by(name: params[:id])
+    @user = @drupal_user.user
+  else
+    @user = current_user
+    @drupal_user = current_user.drupal_user
+  end
+  if current_user && current_user.uid == @user.uid #|| current_user.role == "admin"
+    render :template => "users/edit"
+  else
+    flash[:error] = I18n.t('users_controller.only_user_edit_profile', :user => @user.name).html_safe
+    redirect_to "/profile/"+@user.name
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ followers() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 261
+def followers
+  @title = "Followers"
+  @user  = User.find_by(username: params[:id])
+  @users = @user.followers.paginate(page: params[:page], per_page: 24)
+  render 'show_follow'
+end
+
+ +
+ + + + +
+ + +
+ +
+ following() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 254
+def following
+  @title = "Following"
+  @user  = User.find_by(username: params[:id])
+  @users = @user.following_users.paginate(page: params[:page], per_page: 24)
+  render 'show_follow'
+end
+
+ +
+ + + + +
+ + +
+ +
+ info() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 250
+def info
+  @user = DrupalUser.find_by(name: params[:id])
+end
+
+ +
+ + + + +
+ + +
+ +
+ likes() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 148
+def likes
+  @user = DrupalUser.find_by(name: params[:id])
+  @title = "Liked by "+@user.name
+  @notes = @user.liked_notes
+                .includes([:tag, :comments])
+                .paginate(page: params[:page], per_page: 24)
+  @wikis = @user.liked_pages
+  @tagnames = []
+  @unpaginated = false
+end
+
+ +
+ + + + +
+ + +
+ +
+ list() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 83
+def list
+  # allow admins to view recent users
+  if params[:id]
+    @users = DrupalUser.joins('INNER JOIN rusers ON rusers.username = users.name')
+                        .order("updated_at DESC")
+                        .where('rusers.role = ?', params[:id])
+                        .page(params[:page])
+  else
+    # recently active
+    @users = DrupalUser.select('*, MAX(node.changed) AS last_updated')
+                        .joins(:node)
+                        .group('users.uid')
+                        .where('users.status = 1 AND node.status = 1')
+                        .order("last_updated DESC")
+                        .page(params[:page])
+  end
+  @users = @users.where('users.status = 1') unless current_user && (current_user.role == "admin" || current_user.role == "moderator")
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 5
+def new
+  @spamaway = Spamaway.new
+  @user = User.new
+  @action = "create" # sets the form url
+end
+
+ +
+ + + + +
+ + +
+ +
+ photo() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 229
+def photo
+  @user = DrupalUser.find_by(uid: params[:uid]).user
+  if current_user.uid == @user.uid || current_user.role == "admin"
+    @user.photo = params[:photo]
+    if @user.save!
+      if request.xhr?
+        render :json => { :url => @user.photo_path }
+      else
+        flash[:notice] = I18n.t('users_controller.image_saved')
+        redirect_to @node.path
+      end
+    else
+      flash[:error] = I18n.t('users_controller.image_not_saved')
+      redirect_to "/images/new"
+    end
+  else
+    flash[:error] = I18n.t('users_controller.image_not_saved')
+    redirect_to "/images/new"
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ profile() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 102
+def profile
+  if current_user && params[:id].nil?
+    redirect_to "/profile/#{current_user.username}"
+  else
+    @user = DrupalUser.find_by(name: params[:id])
+    @profile_user = User.find_by(username: params[:id])
+    @title = @user.name
+    @notes = Node.research_notes
+                       .page(params[:page])
+                       .order("nid DESC")
+                       .where(status: 1, uid: @user.uid)
+    @coauthored = @profile_user.coauthored_notes
+                               .page(params[:page])
+                               .order('node_revisions.timestamp DESC')
+    @questions = @user.user.questions
+                           .order('node.nid DESC')
+                           .paginate(:page => params[:page], :per_page => 24)
+    questions = Node.questions
+                          .where(status: 1)
+                          .order('node.nid DESC')
+    @answered_questions = questions.select{|q| q.answers.collect(&:author).include?(@user)}
+    wikis = Revision.order("nid DESC")
+                    .where('node.type' => 'page', 'node.status' => 1, uid: @user.uid)
+                    .joins(:node)
+                    .limit(20)
+    @wikis = wikis.collect(&:parent).uniq
+   
+    # User's social links
+    @github = @profile_user.social_link("github")
+    @twitter = @profile_user.social_link("twitter")
+    @facebook = @profile_user.social_link("facebook")
+    @instagram = @profile_user.social_link("instagram")
+   
+    if @user.status == 0
+      if current_user && (current_user.role == "admin" || current_user.role == "moderator")
+        flash.now[:error] = I18n.t('users_controller.user_has_been_banned')
+      else
+        flash[:error] = I18n.t('users_controller.user_has_been_banned')
+        redirect_to "/"
+      end
+    elsif @user.status == 5
+      flash.now[:warning] = I18n.t('users_controller.user_has_been_moderated')
+    end
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ reset() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 181
+def reset
+  if params[:key] && params[:key] != nil
+    @user = User.find_by(reset_key: params[:key])
+    if @user
+      if params[:user] && params[:user][:password]
+        if @user.username.downcase == params[:user][:username].downcase
+          @user.password = params[:user][:password]
+          @user.password_confirmation = params[:user][:password]
+          @user.reset_key = nil
+          if @user.changed? && @user.save({})
+            flash[:notice] = I18n.t('users_controller.password_change_success')
+            redirect_to "/dashboard"
+          else
+            flash[:error] = I18n.t('users_controller.password_reset_failed').html_safe
+            redirect_to "/"
+          end
+        else
+          flash[:error] = I18n.t('users_controller.password_change_failed')
+        end
+      else
+        # Just display page prompting username & pwd
+      end
+    else
+      flash[:error] = I18n.t('users_controller.password_reset_failed_no_user').html_safe
+      redirect_to "/"
+    end
+
+  elsif params[:email]
+    user = User.find_by(email: params[:email])
+    if user
+      key = user.generate_reset_key
+      user.save({})
+      # send key to user email
+      PasswordResetMailer.reset_notify(user, key) unless user.nil? # respond the same to both successes and failures; security
+    end
+    flash[:notice] = I18n.t('users_controller.password_reset_email')
+    redirect_to "/login"
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ rss() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 159
+def rss
+  if params[:author]
+    @author = DrupalUser.where(name: params[:author], status: 1).first
+    if @author
+      @notes = Node.order("nid DESC")
+                         .where(type: 'note', status: 1, uid: @author.uid)
+                         .limit(20)
+    else
+      flash[:error] = I18n.t('users_controller.no_user_found')
+      redirect_to "/"
+    end
+  else
+  end
+  respond_to do |format|
+    format.rss {
+      render :layout => false
+      response.headers["Content-Type"] = "application/xml; charset=utf-8"
+      response.headers["Access-Control-Allow-Origin"] = "*"
+    }
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ update() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/users_controller.rb, line 42
+def update
+  if current_user
+  @user = current_user
+    @user.attributes = params[:user]
+    @user.save({}) do |result|
+      if result
+        if session[:openid_return_to] # for openid login, redirects back to openid auth process
+          return_to = session[:openid_return_to]
+          session[:openid_return_to] = nil
+          redirect_to return_to
+        else
+          flash[:notice] = I18n.t('users_controller.successful_updated_profile')+"<a href='/dashboard'>"+I18n.t('users_controller.return_dashboard')+" &raquo;</a>"
+          redirect_to "/profile/"+@user.username
+        end
+      else
+        render :template => 'users/edit'
+      end
+    end
+  else
+    flash[:error] = I18n.t('users_controller.only_user_edit_profile', :user => @user.name).html_safe
+    redirect_to "/profile/"+@user.name
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/UsersHelper.html b/doc/app/UsersHelper.html new file mode 100644 index 0000000000..cdd1b292db --- /dev/null +++ b/doc/app/UsersHelper.html @@ -0,0 +1,95 @@ + + + + + + +module UsersHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module UsersHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/WelcomeMailer.html b/doc/app/WelcomeMailer.html new file mode 100644 index 0000000000..3ce779d640 --- /dev/null +++ b/doc/app/WelcomeMailer.html @@ -0,0 +1,168 @@ + + + + + + +class WelcomeMailer - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class WelcomeMailer +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ add_to_list(user, list) + + click to toggle source + +
+ + +
+ +

PasswordResetMailer#reset_notify.deliver

+ + + + +
+
# File app/mailers/welcome_mailer.rb, line 7
+def add_to_list(user, list)
+  subject = 'subscribe'
+  @list = list
+  @footer = feature('email-footer')
+  mail(to: list + '+subscribe@googlegroups.com', subject: subject, from: user.email).deliver
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/WikiController.html b/doc/app/WikiController.html new file mode 100644 index 0000000000..5259377ca9 --- /dev/null +++ b/doc/app/WikiController.html @@ -0,0 +1,1188 @@ + + + + + + +class WikiController - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ class WikiController +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+

Public Instance Methods

+
+ + +
+ +
+ comments() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 423
+def comments
+  show
+  render :show
+end
+
+ +
+ + + + +
+ + +
+ +
+ create() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 133
+def create
+  if current_user.drupal_user.status == 1
+    # we no longer allow custom urls, just titles which are parameterized automatically into urls
+    # slug = params[:title].parameterize
+    # slug = params[:id].parameterize if params[:id] != "" && !params[:id].nil?
+    # slug = params[:url].parameterize if params[:url] != "" && !params[:url].nil?
+    saved, @node, @revision = Node.new_wiki(uid:   current_user.uid,
+                                            title: params[:title],
+                                            body:  params[:body])
+    if saved
+      flash[:notice] = I18n.t('wiki_controller.wiki_page_created')
+      if params[:main_image] && params[:main_image] != ''
+        img = Image.find params[:main_image]
+        img.nid = @node.id
+        img.save
+      end
+      redirect_to @node.path
+    else
+      render action: :edit
+    end
+  else
+    flash.keep[:error] = I18n.t('wiki_controller.you_have_been_banned').html_safe
+    redirect_to '/logout'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ delete() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 202
+def delete
+  @node = Node.find(params[:id])
+  if current_user && current_user.role == 'admin'
+    @node.destroy
+    flash[:notice] = I18n.t('wiki_controller.wiki_page_deleted')
+    redirect_to '/dashboard'
+  else
+    flash[:error] = I18n.t('wiki_controller.only_admins_delete_pages')
+    redirect_to @node.path
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ diff() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 280
+def diff
+  @a = Revision.find_by(vid: params[:a])
+  @b = Revision.find_by(vid: params[:b])
+  if @a.body == @b.body
+    render text: I18n.t('wiki_controller.lead_image_or_title_change').html_safe
+  else
+    render partial: 'wiki/diff'
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ edit() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 90
+def edit
+  @node = if params[:lang]
+            Node.find_wiki(params[:lang] + '/' + params[:id])
+          else
+            Node.find_wiki(params[:id])
+          end
+  if @node.has_tag('locked') && (current_user.role != 'admin' && current_user.role != 'moderator')
+    flash[:warning] = "This page is <a href='/wiki/power-tags#Locking'>locked</a>, and only <a href='/wiki/moderators'>moderators</a> can edit it."
+    redirect_to @node.path
+  end
+  if ((Time.now.to_i - @node.latest.timestamp) < 5.minutes.to_i) && @node.latest.author.uid != current_user.uid
+    flash.now[:warning] = I18n.t('wiki_controller.someone_clicked_edit_5_minutes_ago')
+  end
+  # we could do this...
+  # @node.locked = true
+  # @node.save
+  @title = I18n.t('wiki_controller.editing', title: @node.title).html_safe
+
+  @tags = @node.tags
+end
+
+ +
+ + + + +
+ + +
+ +
+ index() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 290
+def index
+  @title = I18n.t('wiki_controller.wiki')
+
+  order_string = if params[:order] == 'alphabetic'
+                   'node_revisions.title ASC'
+                 else
+                   'node_revisions.timestamp DESC'
+                 end
+
+  @wikis = Node.includes(:revision)
+               .references(:node_revisions)
+               .group('node_revisions.nid')
+               .order(order_string)
+               .where("node_revisions.status = 1 AND node.status = 1 AND (type = 'page' OR type = 'tool' OR type = 'place')")
+               .page(params[:page])
+
+  @paginated = true
+end
+
+ +
+ + + + +
+ + +
+ +
+ liked() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 334
+def liked
+  @title = I18n.t('wiki_controller.well_liked_wiki_pages')
+  @wikis = Node.limit(40)
+               .order('node.cached_likes DESC')
+               .where("status = 1 AND nid != 259 AND (type = 'page' OR type = 'tool' OR type = 'place') AND cached_likes > 0")
+  render template: 'wiki/index'
+end
+
+ +
+ + + + +
+ + +
+ +
+ methods() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 369
+def methods
+  @nodes = Node.where(status: 1, type: ['page'])
+               .where('term_data.name = ?', 'method')
+               .includes(:revision, :tag)
+               .references(:node_revision)
+               .order('node_revisions.timestamp DESC')
+  # deprecating the following in favor of javascript implementation in /app/assets/javascripts/methods.js
+  if params[:topic]
+    nids = @nodes.collect(&:nid) || []
+    @notes = Node.where(status: 1, type: ['page'])
+                 .where('node.nid IN (?)', nids)
+                 .where('(type = "note" OR type = "page" OR type = "map") AND node.status = 1 AND (node.title LIKE ? OR node_revisions.title LIKE ? OR node_revisions.body LIKE ? OR term_data.name = ?)',
+                        '%' + params[:topic] + '%',
+                        '%' + params[:topic] + '%',
+                        '%' + params[:topic] + '%',
+                        params[:topic])
+                 .includes(:revision, :tag)
+                 .references(:node_revision, :term_data)
+                 .order('node_revisions.timestamp DESC')
+  end
+  if params[:topic]
+    nids = @nodes.collect(&:nid) || []
+    @nodes = Node.where(status: 1, type: ['page'])
+                 .where('node.nid IN (?)', nids)
+                 .where('(type = "note" OR type = "page" OR type = "map") AND node.status = 1 AND (node.title LIKE ? OR node_revisions.title LIKE ? OR node_revisions.body LIKE ? OR term_data.name = ?)',
+                        '%' + params[:topic] + '%',
+                        '%' + params[:topic] + '%',
+                        '%' + params[:topic] + '%',
+                        params[:topic])
+                 .includes(:revision, :tag)
+                 .references(:node_revision, :term_data)
+                 .order('node_revisions.timestamp DESC')
+  end
+
+  @unpaginated = true
+  @topics = [
+    'agriculture',
+    'drinking-water',
+    'fracking',
+    'indoor-air',
+    'chemicals',
+    'industry',
+    'land-use',
+    'land-change',
+    'mining',
+    'oil-and-gas',
+    'transportation',
+    'urban-planning',
+    'sensors',
+    'community-organizing'
+  ]
+  render template: 'wiki/methods'
+end
+
+ +
+ + + + +
+ + +
+ +
+ new() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 111
+def new
+  @node = Node.new
+  if params[:n] && !params[:body] # use another node body as a template
+    node = Node.find(params[:n])
+    params[:body] = node.latest.body if node && node.latest
+  end
+  @tags = []
+  if params[:id]
+    flash.now[:notice] = I18n.t('wiki_controller.page_does_not_exist_create')
+    title = params[:id].tr('-', ' ')
+    @related = Node.limit(10)
+                   .order('node.nid DESC')
+                   .where('type = "page" AND node.status = 1 AND (node.title LIKE ? OR node_revisions.body LIKE ?)', '%' + title + '%', '%' + title + '%')
+                   .includes(:revision)
+                   .references(:node_revisions)
+    tag = Tag.find_by(name: params[:id]) # add page name as a tag, too
+    @tags << tag if tag
+    @related += Tag.find_nodes_by_type(@tags.collect(&:name), 'page', 10)
+  end
+  render template: 'wiki/edit'
+end
+
+ +
+ + + + +
+ + + + + +
+ +
+ raw() + + click to toggle source + +
+ + +
+ +

display a revision, raw

+ + + + +
+
# File app/controllers/wiki_controller.rb, line 85
+def raw
+  response.headers['Content-Type'] = 'text/plain; charset=utf-8'
+  render text: Revision.find(params[:id]).body
+end
+
+ +
+ + + + +
+ + +
+ +
+ replace() + + click to toggle source + +
+ + +
+ +

replace subsection of wiki body

+ + + + +
+
# File app/controllers/wiki_controller.rb, line 343
+def replace
+  @node = Node.find(params[:id])
+  if params[:before] && params[:after]
+    # during round trip, strings are getting "\r\n" newlines converted to "\n",
+    # so we're ensuring they remain "\r\n"; this may vary based on platform, unfortunately
+    before = params[:before].gsub("\n", "\r\n")
+    after  = params[:after]#.gsub( "\n", "\r\n")
+    if output = @node.replace(before, after, current_user)
+      flash[:notice] = 'New revision created with your additions.' unless request.xhr?
+    else
+      flash[:error] = 'There was a problem replacing that text.' unless request.xhr?
+    end
+  else
+    flash[:error] = "You must specify 'before' and 'after' terms to replace content in a wiki page."
+  end
+  if request.xhr?
+    render json: output
+  else
+    redirect_to @node.path
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ revert() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 214
+def revert
+  revision = Revision.find params[:id]
+  node = revision.parent
+  if current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    new_rev = revision.dup
+    new_rev.timestamp = DateTime.now.to_i
+    if new_rev.save!
+      flash[:notice] = I18n.t('wiki_controller.wiki_page_reverted')
+    else
+      flash[:error] = I18n.t('wiki_controller.problem_reverting')
+    end
+  else
+    flash[:error] = I18n.t('wiki_controller.moderators_admin_delete_pages')
+  end
+  redirect_to node.path
+end
+
+ +
+ + + + +
+ + +
+ +
+ revision() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 260
+def revision
+  @node = Node.find_wiki(params[:id])
+  @tags = @node.tags
+  @tagnames = @tags.collect(&:name)
+  @unpaginated = true
+  @is_revision = true
+  set_sidebar :tags, @tagnames, videos: true
+  @revision = Revision.find_by_nid_and_vid(@node.id, params[:vid])
+  if @revision.nil?
+    flash[:error] = I18n.t('wiki_controller.revision_not_found')
+    redirect_to action: 'revisions'
+  elsif @revision.status == 1 || current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    @title = I18n.t('wiki_controller.revisions_for', title: @revision.title).html_safe
+    render template: 'wiki/show'
+  else
+    flash[:error] = I18n.t('wiki_controller.revision_has_been_moderated').html_safe
+    redirect_to @node.path
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ revisions() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 248
+def revisions
+  @node = Node.find_wiki(params[:id])
+  if @node
+    @revisions = @node.revisions
+    @revisions = @revisions.where(status: 1) unless current_user && (current_user.role == 'moderator' || current_user.role == 'admin')
+    @title = I18n.t('wiki_controller.revisions_for', title: @node.title).html_safe
+    @tags = @node.tags
+  else
+    flash[:error] = I18n.t('wiki_controller.invalid_wiki_page')
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ root() + + click to toggle source + +
+ + +
+ +

wiki pages which have a root URL, like /about also just redirect anything +else matching /__ to /wiki/__

+ + + + +
+
# File app/controllers/wiki_controller.rb, line 233
+def root
+  @node = Node.find_by_path(params[:id])
+  return if check_and_redirect_node(@node)
+  if @node
+    @revision = @node.latest
+    @title = @revision.title
+    @tags = @node.tags
+    @tagnames = @tags.collect(&:name)
+    render template: 'wiki/show'
+  else
+    # redirects any uncaught requests to example.com/______ to /wiki/____
+    redirect_to '/wiki/' + params[:id]
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ show() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 21
+def show
+  @node = if params[:lang]
+            Node.find_wiki(params[:lang] + '/' + params[:id])
+          else
+            Node.find_wiki(params[:id])
+          end
+
+  if @node && @node.has_power_tag('redirect') && Node.where(nid: @node.power_tag('redirect')).exists?
+    if current_user.nil? || (current_user.role != 'admin' && current_user.role != 'moderator')
+      redirect_to Node.find(@node.power_tag('redirect')).path
+      return
+    elsif current_user.role == 'admin' || current_user.role == 'moderator'
+      flash.now[:warning] = "Only moderators and admins see this page, as it is redirected to <a href='#{Node.find(@node.power_tag('redirect')).path}'>#{Node.find(@node.power_tag('redirect')).title}</a>.
+      To remove the redirect, delete the tag beginning with 'redirect:'"
+    end
+  end
+
+  if @node && @node.has_power_tag('abtest') && !Node.where(nid: @node.power_tag('abtest')).empty?
+    if current_user.nil? || (current_user.role != 'admin' && current_user.role != 'moderator')
+      if Random.rand(2) == 0
+        redirect_to Node.find(@node.power_tag('abtest')).path
+        return
+      end
+    elsif current_user.role == 'admin' || current_user.role == 'moderator'
+      flash.now[:warning] = "Only moderators and admins see this page, as it is redirected to #{Node.find(@node.power_tag('abtest')).title} roughly around 50% of the time.
+      To remove this behavior, delete the tag beginning with 'abtest:'"
+    end
+  end
+
+  # if request.path != @node.path && request.path != '/wiki/' + @node.nid.to_s
+  #   return redirect_to @node.path, :status => :moved_permanently
+  # end
+
+  return if check_and_redirect_node(@node)
+  if !@node.nil? # it's a place page!
+    @tags = @node.tags
+    @tags += [Tag.find_by(name: params[:id])] if Tag.find_by(name: params[:id])
+  else # it's a new wiki page!
+    @title = I18n.t('wiki_controller.new_wiki_page')
+    if current_user
+      new
+    else
+      flash[:warning] = I18n.t('wiki_controller.pages_does_not_exist')
+      redirect_to '/login'
+    end
+  end
+
+  unless @title # the page exists
+    if @node.status == 0
+      flash[:warning] = I18n.t('wiki_controller.page_moderated_as_spam')
+      redirect_to '/wiki'
+    end
+    @tagnames = @tags.collect(&:name)
+    set_sidebar :tags, @tagnames, videos: true
+    @wikis = Tag.find_pages(@node.slug_from_path, 30) if @node.has_tag('chapter') || @node.has_tag('tabbed:wikis')
+
+    impressionist(@node, 'show', unique: [:ip_address])
+    @revision = @node.latest # needed for template, so it can be used for past revisions too in the "revision" action
+    @title = @revision.title
+  end
+  @unpaginated = true
+end
+
+ +
+ + + + +
+ + +
+ +
+ stale() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 309
+def stale
+  @title = I18n.t('wiki_controller.wiki')
+
+  @wikis = Node.includes(:revision)
+               .references(:node_revisions)
+               .group('node_revisions.nid')
+               .order('node_revisions.timestamp ASC')
+               .where("node_revisions.status = 1 AND node.status = 1 AND (type = 'page' OR type = 'tool' OR type = 'place')")
+               .page(params[:page])
+               
+  @paginated = true
+  render template: 'wiki/index'
+end
+
+ +
+ + + + +
+ + +
+ +
+ subdomain() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 6
+def subdomain
+  url = "//#{request.host}/wiki/"
+  case request.subdomain
+  when 'new-york-city',
+       'gulf-coast',
+       'boston',
+       'espana' then
+    redirect_to url + request.subdomain
+  when 'nyc'
+    redirect_to url + 'new-york-city'
+  else
+    redirect_to url
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+ techniques() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 365
+def techniques
+  redirect_to '/methods', status: 302
+end
+
+ +
+ + + + +
+ + +
+ +
+ update() + + click to toggle source + +
+ + +
+ + + + + + +
+
# File app/controllers/wiki_controller.rb, line 159
+def update
+  @node = Node.find(params[:id])
+  @revision = @node.new_revision(uid:   current_user.uid,
+                                 title: params[:title],
+                                 body:  params[:body])
+  if @node.has_tag('locked') && (current_user.role != 'admin' && current_user.role != 'moderator')
+    flash[:warning] = "This page is <a href='/wiki/power-tags#Locking'>locked</a>, and only <a href='/wiki/moderators'>moderators</a> can update it."
+    redirect_to @node.path
+
+  elsif @revision.valid?
+    ActiveRecord::Base.transaction do
+      @revision.save
+      @node.vid = @revision.vid
+      # update vid (version id) of main image
+      if @node.drupal_main_image && params[:main_image].nil?
+        i = @node.drupal_main_image
+        i.vid = @revision.vid
+        i.save
+      end
+      @node.title = @revision.title
+      # save main image
+      if params[:main_image] && params[:main_image] != ''
+        begin
+          img = Image.find params[:main_image]
+          unless img.nil?
+            img.nid = @node.id
+            @node.main_image_id = img.id
+            img.save
+          end
+        rescue
+        end
+      end
+      @node.save
+    end
+    flash[:notice] = I18n.t('wiki_controller.edits_saved')
+    redirect_to @node.path
+  else
+    flash[:error] = I18n.t('wiki_controller.edit_could_not_be_saved')
+    render action: :edit
+    # redirect_to "/wiki/edit/"+@node.slug
+  end
+end
+
+ +
+ + + + +
+ + +
+ +
+
+ + + + diff --git a/doc/app/WikiHelper.html b/doc/app/WikiHelper.html new file mode 100644 index 0000000000..621d1d4f2e --- /dev/null +++ b/doc/app/WikiHelper.html @@ -0,0 +1,95 @@ + + + + + + +module WikiHelper - Rails Application Documentation + + + + + + + + + + + + + + +
+

+ module WikiHelper +

+ +
+ +
+ + + + +
+ + + + + + + + + +
+
+ + + + diff --git a/doc/app/created.rid b/doc/app/created.rid new file mode 100644 index 0000000000..4261b7ed25 --- /dev/null +++ b/doc/app/created.rid @@ -0,0 +1,95 @@ +Tue, 16 Jan 2018 09:32:59 -0500 +README.rdoc Sat, 29 Apr 2017 20:53:17 -0400 +app/api/srch/api.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/api/srch/search.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/api/srch/typeahead.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/admin_controller.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/answer_like_controller.rb Sat, 09 Dec 2017 13:59:31 -0500 +app/controllers/answers_controller.rb Sat, 09 Dec 2017 13:59:31 -0500 +app/controllers/application_controller.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/controllers/comment_controller.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/controllers/editor_controller.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/features_controller.rb Fri, 12 Jan 2018 11:30:32 -0500 +app/controllers/home_controller.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/images_controller.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/controllers/legacy_controller.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/like_controller.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/map_controller.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/notes_controller.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/openid_controller.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/controllers/questions_controller.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/controllers/relationships_controller.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/controllers/searches_controller.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/controllers/settings_controller.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/stats_controller.rb Fri, 12 Jan 2018 11:30:32 -0500 +app/controllers/subscription_controller.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/controllers/tag_controller.rb Fri, 12 Jan 2018 15:45:10 -0500 +app/controllers/talk_controller.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/controllers/user_sessions_controller.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/controllers/user_tags_controller.rb Fri, 12 Jan 2018 09:21:32 -0500 +app/controllers/users_controller.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/controllers/wiki_controller.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/helpers/admin_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/application_helper.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/helpers/comment_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/features_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/home_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/map_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/notes_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/openid_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/redirect_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/searches_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/tag_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/user_tags_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/users_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/helpers/wiki_helper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/mailers/admin_mailer.rb Sat, 09 Dec 2017 13:59:31 -0500 +app/mailers/answer_mailer.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/mailers/comment_mailer.rb Sat, 09 Dec 2017 13:59:31 -0500 +app/mailers/password_reset_mailer.rb Sat, 09 Dec 2017 13:59:31 -0500 +app/mailers/subscription_mailer.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/mailers/welcome_mailer.rb Sat, 09 Dec 2017 13:59:31 -0500 +app/models/answer.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/models/answer_selection.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/models/comment.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/models/concerns/comments_shared.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/models/concerns/node_shared.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/models/doc_list.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/doc_result.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/drupal_content_field_image_gallery.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/drupal_content_field_map_editor.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/drupal_content_field_mapper.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/drupal_content_type_map.rb Sat, 09 Dec 2017 13:59:31 -0500 +app/models/drupal_file.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/drupal_main_image.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/drupal_profile_field.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/drupal_profile_value.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/drupal_upload.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/drupal_user.rb Fri, 12 Jan 2018 15:45:10 -0500 +app/models/image.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/models/node.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/models/node_selection.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/models/node_tag.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/models/relationship.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/revision.rb Fri, 12 Jan 2018 15:45:10 -0500 +app/models/search_request.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/spamaway.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/tableless.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/tag.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/models/tag_list.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/tag_result.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/tag_selection.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/models/user.rb Fri, 12 Jan 2018 16:58:57 -0500 +app/models/user_selection.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/user_session.rb Thu, 16 Nov 2017 17:43:38 -0500 +app/models/user_tag.rb Tue, 12 Dec 2017 23:47:51 -0500 +app/services/search_service.rb Fri, 12 Jan 2018 12:21:54 -0500 +app/services/typeahead_service.rb Fri, 12 Jan 2018 15:45:10 -0500 +lib/authlogic_openid/authlogic_openid.rb Sat, 29 Apr 2017 20:53:17 -0400 +lib/authlogic_openid/authlogic_openid/acts_as_authentic.rb Sat, 29 Apr 2017 20:53:17 -0400 +lib/authlogic_openid/authlogic_openid/session.rb Sat, 29 Apr 2017 20:53:17 -0400 +lib/authlogic_openid/authlogic_openid/version.rb Sat, 29 Apr 2017 20:53:17 -0400 +lib/dynamic_form/action_view/helpers/dynamic_form.rb Sat, 29 Apr 2017 20:53:17 -0400 +lib/dynamic_form/dynamic_form.rb Sat, 29 Apr 2017 20:53:17 -0400 +lib/open_id_authentication/open_id_authentication.rb Sat, 29 Apr 2017 20:53:17 -0400 +lib/solr_toggle/solr_toggle.rb Tue, 19 Sep 2017 13:30:04 -0400 diff --git a/doc/app/css/fonts.css b/doc/app/css/fonts.css new file mode 100644 index 0000000000..e9e721183b --- /dev/null +++ b/doc/app/css/fonts.css @@ -0,0 +1,167 @@ +/* + * Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + * with Reserved Font Name "Source". All Rights Reserved. Source is a + * trademark of Adobe Systems Incorporated in the United States and/or other + * countries. + * + * This Font Software is licensed under the SIL Open Font License, Version + * 1.1. + * + * This license is copied below, and is also available with a FAQ at: + * http://scripts.sil.org/OFL + */ + +@font-face { + font-family: "Source Code Pro"; + font-style: normal; + font-weight: 400; + src: local("Source Code Pro"), + local("SourceCodePro-Regular"), + url("fonts/SourceCodePro-Regular.ttf") format("truetype"); +} + +@font-face { + font-family: "Source Code Pro"; + font-style: normal; + font-weight: 700; + src: local("Source Code Pro Bold"), + local("SourceCodePro-Bold"), + url("fonts/SourceCodePro-Bold.ttf") format("truetype"); +} + +/* + * Copyright (c) 2010, Łukasz Dziedzic (dziedzic@typoland.com), + * with Reserved Font Name Lato. + * + * This Font Software is licensed under the SIL Open Font License, Version + * 1.1. + * + * This license is copied below, and is also available with a FAQ at: + * http://scripts.sil.org/OFL + */ + +@font-face { + font-family: "Lato"; + font-style: normal; + font-weight: 300; + src: local("Lato Light"), + local("Lato-Light"), + url("fonts/Lato-Light.ttf") format("truetype"); +} + +@font-face { + font-family: "Lato"; + font-style: italic; + font-weight: 300; + src: local("Lato Light Italic"), + local("Lato-LightItalic"), + url("fonts/Lato-LightItalic.ttf") format("truetype"); +} + +@font-face { + font-family: "Lato"; + font-style: normal; + font-weight: 700; + src: local("Lato Regular"), + local("Lato-Regular"), + url("fonts/Lato-Regular.ttf") format("truetype"); +} + +@font-face { + font-family: "Lato"; + font-style: italic; + font-weight: 700; + src: local("Lato Italic"), + local("Lato-Italic"), + url("fonts/Lato-RegularItalic.ttf") format("truetype"); +} + +/* + * ----------------------------------------------------------- + * SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + * ----------------------------------------------------------- + * + * PREAMBLE + * The goals of the Open Font License (OFL) are to stimulate worldwide + * development of collaborative font projects, to support the font creation + * efforts of academic and linguistic communities, and to provide a free and + * open framework in which fonts may be shared and improved in partnership + * with others. + * + * The OFL allows the licensed fonts to be used, studied, modified and + * redistributed freely as long as they are not sold by themselves. The + * fonts, including any derivative works, can be bundled, embedded, + * redistributed and/or sold with any software provided that any reserved + * names are not used by derivative works. The fonts and derivatives, + * however, cannot be released under any other type of license. The + * requirement for fonts to remain under this license does not apply + * to any document created using the fonts or their derivatives. + * + * DEFINITIONS + * "Font Software" refers to the set of files released by the Copyright + * Holder(s) under this license and clearly marked as such. This may + * include source files, build scripts and documentation. + * + * "Reserved Font Name" refers to any names specified as such after the + * copyright statement(s). + * + * "Original Version" refers to the collection of Font Software components as + * distributed by the Copyright Holder(s). + * + * "Modified Version" refers to any derivative made by adding to, deleting, + * or substituting -- in part or in whole -- any of the components of the + * Original Version, by changing formats or by porting the Font Software to a + * new environment. + * + * "Author" refers to any designer, engineer, programmer, technical + * writer or other person who contributed to the Font Software. + * + * PERMISSION & CONDITIONS + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of the Font Software, to use, study, copy, merge, embed, modify, + * redistribute, and sell modified and unmodified copies of the Font + * Software, subject to the following conditions: + * + * 1) Neither the Font Software nor any of its individual components, + * in Original or Modified Versions, may be sold by itself. + * + * 2) Original or Modified Versions of the Font Software may be bundled, + * redistributed and/or sold with any software, provided that each copy + * contains the above copyright notice and this license. These can be + * included either as stand-alone text files, human-readable headers or + * in the appropriate machine-readable metadata fields within text or + * binary files as long as those fields can be easily viewed by the user. + * + * 3) No Modified Version of the Font Software may use the Reserved Font + * Name(s) unless explicit written permission is granted by the corresponding + * Copyright Holder. This restriction only applies to the primary font name as + * presented to the users. + * + * 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font + * Software shall not be used to promote, endorse or advertise any + * Modified Version, except to acknowledge the contribution(s) of the + * Copyright Holder(s) and the Author(s) or with their explicit written + * permission. + * + * 5) The Font Software, modified or unmodified, in part or in whole, + * must be distributed entirely under this license, and must not be + * distributed under any other license. The requirement for fonts to + * remain under this license does not apply to any document created + * using the Font Software. + * + * TERMINATION + * This license becomes null and void if any of the above conditions are + * not met. + * + * DISCLAIMER + * THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + * OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL + * DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM + * OTHER DEALINGS IN THE FONT SOFTWARE. + */ + diff --git a/doc/app/css/rdoc.css b/doc/app/css/rdoc.css new file mode 100644 index 0000000000..2f4dca7e08 --- /dev/null +++ b/doc/app/css/rdoc.css @@ -0,0 +1,590 @@ +/* + * "Darkfish" Rdoc CSS + * $Id: rdoc.css 54 2009-01-27 01:09:48Z deveiant $ + * + * Author: Michael Granger + * + */ + +/* vim: ft=css et sw=2 ts=2 sts=2 */ +/* Base Green is: #6C8C22 */ + +* { padding: 0; margin: 0; } + +body { + background: #fafafa; + font-family: Lato, sans-serif; + font-weight: 300; +} + +h1 span, +h2 span, +h3 span, +h4 span, +h5 span, +h6 span { + position: relative; + + display: none; + padding-left: 1em; + line-height: 0; + vertical-align: baseline; + font-size: 10px; +} + +h1 span { top: -1.3em; } +h2 span { top: -1.2em; } +h3 span { top: -1.0em; } +h4 span { top: -0.8em; } +h5 span { top: -0.5em; } +h6 span { top: -0.5em; } + +h1:hover span, +h2:hover span, +h3:hover span, +h4:hover span, +h5:hover span, +h6:hover span { + display: inline; +} + +:link, +:visited { + color: #6C8C22; + text-decoration: none; +} + +:link:hover, +:visited:hover { + border-bottom: 1px dotted #6C8C22; +} + +code, +pre { + font-family: "Source Code Pro", Monaco, monospace; +} + +/* @group Generic Classes */ + +.initially-hidden { + display: none; +} + +#search-field { + width: 98%; + background: white; + border: none; + height: 1.5em; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + text-align: left; +} +#search-field:focus { + background: #f1edba; +} +#search-field:-moz-placeholder, +#search-field::-webkit-input-placeholder { + font-weight: bold; + color: #666; +} + +.missing-docs { + font-size: 120%; + background: white url(images/wrench_orange.png) no-repeat 4px center; + color: #ccc; + line-height: 2em; + border: 1px solid #d00; + opacity: 1; + padding-left: 20px; + text-indent: 24px; + letter-spacing: 3px; + font-weight: bold; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; +} + +.target-section { + border: 2px solid #dcce90; + border-left-width: 8px; + padding: 0 1em; + background: #fff3c2; +} + +/* @end */ + +/* @group Index Page, Standalone file pages */ +.table-of-contents ul { + margin: 1em; + list-style: none; +} + +.table-of-contents ul ul { + margin-top: 0.25em; +} + +.table-of-contents ul :link, +.table-of-contents ul :visited { + font-size: 16px; +} + +.table-of-contents li { + margin-bottom: 0.25em; +} + +.table-of-contents li .toc-toggle { + width: 16px; + height: 16px; + background: url(images/add.png) no-repeat; +} + +.table-of-contents li .toc-toggle.open { + background: url(images/delete.png) no-repeat; +} + +/* @end */ + +/* @group Top-Level Structure */ + +nav { + float: left; + width: 260px; + font-family: Helvetica, sans-serif; + font-size: 14px; +} + +main { + display: block; + margin: 0 2em 5em 260px; + padding-left: 20px; + min-width: 340px; + font-size: 16px; +} + +main h1, +main h2, +main h3, +main h4, +main h5, +main h6 { + font-family: Helvetica, sans-serif; +} + +.table-of-contents main { + margin-left: 2em; +} + +#validator-badges { + clear: both; + margin: 1em 1em 2em; + font-size: smaller; +} + +/* @end */ + +/* @group navigation */ +nav { + margin-bottom: 1em; +} + +nav .nav-section { + margin-top: 2em; + border-top: 2px solid #aaa; + font-size: 90%; + overflow: hidden; +} + +nav h2 { + margin: 0; + padding: 2px 8px 2px 8px; + background-color: #e8e8e8; + color: #555; + font-size: 125%; + text-align: center; +} + +nav h3, +#table-of-contents-navigation { + margin: 0; + padding: 2px 8px 2px 8px; + text-align: right; + background-color: #e8e8e8; + color: #555; +} + +nav ul, +nav dl, +nav p { + padding: 4px 8px 0; + list-style: none; +} + +#project-navigation .nav-section { + margin: 0; + border-top: 0; +} + +#home-section h2 { + text-align: center; +} + +#table-of-contents-navigation { + font-size: 1.2em; + font-weight: bold; + text-align: center; +} + +#search-section { + margin-top: 0; + border-top: 0; +} + +#search-field-wrapper { + border-top: 1px solid #aaa; + border-bottom: 1px solid #aaa; + padding: 3px 8px; + background-color: #e8e8e8; + color: #555; +} + +ul.link-list li { + white-space: nowrap; + line-height: 1.4em; +} + +ul.link-list .type { + font-size: 8px; + text-transform: uppercase; + color: white; + background: #969696; + padding: 2px 4px; + -webkit-border-radius: 5px; +} + +.calls-super { + background: url(images/arrow_up.png) no-repeat right center; +} + +/* @end */ + +/* @group Documentation Section */ +main { + color: #333; +} + +main > h1:first-child, +main > h2:first-child, +main > h3:first-child, +main > h4:first-child, +main > h5:first-child, +main > h6:first-child { + margin-top: 0px; +} + +main sup { + vertical-align: super; + font-size: 0.8em; +} + +/* The heading with the class name */ +main h1[class] { + margin-top: 0; + margin-bottom: 1em; + font-size: 2em; + color: #6C8C22; +} + +main h1 { + margin: 2em 0 0.5em; + font-size: 1.7em; +} + +main h2 { + margin: 2em 0 0.5em; + font-size: 1.5em; +} + +main h3 { + margin: 2em 0 0.5em; + font-size: 1.2em; +} + +main h4 { + margin: 2em 0 0.5em; + font-size: 1.1em; +} + +main h5 { + margin: 2em 0 0.5em; + font-size: 1em; +} + +main h6 { + margin: 2em 0 0.5em; + font-size: 1em; +} + +main p { + margin: 0 0 0.5em; + line-height: 1.4em; +} + +main pre { + margin: 1.2em 0.5em; + padding: 1em; + font-size: 0.8em; +} + +main hr { + margin: 1.5em 1em; + border: 2px solid #ddd; +} + +main blockquote { + margin: 0 2em 1.2em 1.2em; + padding-left: 0.5em; + border-left: 2px solid #ddd; +} + +main ol, +main ul { + margin: 1em 2em; +} + +main li > p { + margin-bottom: 0.5em; +} + +main dl { + margin: 1em 0.5em; +} + +main dt { + margin-bottom: 0.5em; + font-weight: bold; +} + +main dd { + margin: 0 1em 1em 0.5em; +} + +main header h2 { + margin-top: 2em; + border-width: 0; + border-top: 4px solid #bbb; + font-size: 130%; +} + +main header h3 { + margin: 2em 0 1.5em; + border-width: 0; + border-top: 3px solid #bbb; + font-size: 120%; +} + +.documentation-section-title { + position: relative; +} +.documentation-section-title .section-click-top { + position: absolute; + top: 6px; + left: 12px; + font-size: 10px; + color: #9b9877; + visibility: hidden; + padding-left: 0.5px; +} + +.documentation-section-title:hover .section-click-top { + visibility: visible; +} + +.constants-list > dl { + margin: 1em 0 2em; + border: 0; +} + +.constants-list > dl dt { + margin-bottom: 0.75em; + padding-left: 0; + font-family: "Source Code Pro", Monaco, monospace; + font-size: 110%; +} + +.constants-list > dl dt a { + color: inherit; +} + +.constants-list > dl dd { + margin: 0 0 2em 0; + padding: 0; + color: #666; +} + +.documentation-section h2 { + position: relative; +} + +.documentation-section h2 a { + position: absolute; + top: 8px; + right: 10px; + font-size: 12px; + color: #9b9877; + visibility: hidden; +} + +.documentation-section h2:hover a { + visibility: visible; +} + +/* @group Method Details */ + +main .method-source-code { + display: none; +} + +main .method-description .method-calls-super { + color: #333; + font-weight: bold; +} + +main .method-detail { + margin-bottom: 2.5em; + cursor: pointer; +} + +main .method-detail:target { + margin-left: -10px; + border-left: 10px solid #f1edba; +} + +main .method-heading { + position: relative; + font-family: "Source Code Pro", Monaco, monospace; + font-size: 110%; + font-weight: bold; + color: #333; +} +main .method-heading :link, +main .method-heading :visited { + color: inherit; +} +main .method-click-advice { + position: absolute; + top: 2px; + right: 5px; + font-size: 12px; + color: #9b9877; + visibility: hidden; + padding-right: 20px; + line-height: 20px; + background: url(images/zoom.png) no-repeat right top; +} +main .method-heading:hover .method-click-advice { + visibility: visible; +} + +main .method-alias .method-heading { + color: #666; +} + +main .method-description, +main .aliases { + margin-top: 0.75em; + color: #333; +} + +main .aliases { + padding-top: 4px; + font-style: italic; + cursor: default; +} +main .method-description ul { + margin-left: 1.5em; +} + +main #attribute-method-details .method-detail:hover { + background-color: transparent; + cursor: default; +} +main .attribute-access-type { + text-transform: uppercase; + padding: 0 1em; +} +/* @end */ + +/* @end */ + +/* @group Source Code */ + +pre { + margin: 0.5em 0; + border: 1px dashed #999; + padding: 0.5em; + background: #262626; + color: white; + overflow: auto; +} + +.ruby-constant { color: #7fffd4; background: transparent; } +.ruby-keyword { color: #00ffff; background: transparent; } +.ruby-ivar { color: #eedd82; background: transparent; } +.ruby-operator { color: #00ffee; background: transparent; } +.ruby-identifier { color: #ffdead; background: transparent; } +.ruby-node { color: #ffa07a; background: transparent; } +.ruby-comment { color: #dc0000; background: transparent; } +.ruby-regexp { color: #ffa07a; background: transparent; } +.ruby-value { color: #7fffd4; background: transparent; } + +/* @end */ + + +/* @group search results */ +#search-results { + font-family: Lato, sans-serif; + font-weight: 300; +} + +#search-results .search-match { + font-family: Helvetica, sans-serif; + font-weight: normal; +} + +#search-results .search-selected { + background: #e8e8e8; + border-bottom: 1px solid transparent; +} + +#search-results li { + list-style: none; + border-bottom: 1px solid #aaa; + margin-bottom: 0.5em; +} + +#search-results li:last-child { + border-bottom: none; + margin-bottom: 0; +} + +#search-results li p { + padding: 0; + margin: 0.5em; +} + +#search-results .search-namespace { + font-weight: bold; +} + +#search-results li em { + background: yellow; + font-style: normal; +} + +#search-results pre { + margin: 0.5em; + font-family: "Source Code Pro", Monaco, monospace; +} + +/* @end */ + diff --git a/doc/app/fonts/Lato-Light.ttf b/doc/app/fonts/Lato-Light.ttf new file mode 100644 index 0000000000..b49dd43729 Binary files /dev/null and b/doc/app/fonts/Lato-Light.ttf differ diff --git a/doc/app/fonts/Lato-LightItalic.ttf b/doc/app/fonts/Lato-LightItalic.ttf new file mode 100644 index 0000000000..7959fef075 Binary files /dev/null and b/doc/app/fonts/Lato-LightItalic.ttf differ diff --git a/doc/app/fonts/Lato-Regular.ttf b/doc/app/fonts/Lato-Regular.ttf new file mode 100644 index 0000000000..839cd589dc Binary files /dev/null and b/doc/app/fonts/Lato-Regular.ttf differ diff --git a/doc/app/fonts/Lato-RegularItalic.ttf b/doc/app/fonts/Lato-RegularItalic.ttf new file mode 100644 index 0000000000..bababa09e3 Binary files /dev/null and b/doc/app/fonts/Lato-RegularItalic.ttf differ diff --git a/doc/app/fonts/SourceCodePro-Bold.ttf b/doc/app/fonts/SourceCodePro-Bold.ttf new file mode 100644 index 0000000000..61e3090c1c Binary files /dev/null and b/doc/app/fonts/SourceCodePro-Bold.ttf differ diff --git a/doc/app/fonts/SourceCodePro-Regular.ttf b/doc/app/fonts/SourceCodePro-Regular.ttf new file mode 100644 index 0000000000..85686d967d Binary files /dev/null and b/doc/app/fonts/SourceCodePro-Regular.ttf differ diff --git a/doc/app/images/add.png b/doc/app/images/add.png new file mode 100644 index 0000000000..6332fefea4 Binary files /dev/null and b/doc/app/images/add.png differ diff --git a/doc/app/images/arrow_up.png b/doc/app/images/arrow_up.png new file mode 100644 index 0000000000..1ebb193243 Binary files /dev/null and b/doc/app/images/arrow_up.png differ diff --git a/doc/app/images/brick.png b/doc/app/images/brick.png new file mode 100644 index 0000000000..7851cf34c9 Binary files /dev/null and b/doc/app/images/brick.png differ diff --git a/doc/app/images/brick_link.png b/doc/app/images/brick_link.png new file mode 100644 index 0000000000..9ebf013a23 Binary files /dev/null and b/doc/app/images/brick_link.png differ diff --git a/doc/app/images/bug.png b/doc/app/images/bug.png new file mode 100644 index 0000000000..2d5fb90ec6 Binary files /dev/null and b/doc/app/images/bug.png differ diff --git a/doc/app/images/bullet_black.png b/doc/app/images/bullet_black.png new file mode 100644 index 0000000000..57619706d1 Binary files /dev/null and b/doc/app/images/bullet_black.png differ diff --git a/doc/app/images/bullet_toggle_minus.png b/doc/app/images/bullet_toggle_minus.png new file mode 100644 index 0000000000..b47ce55f68 Binary files /dev/null and b/doc/app/images/bullet_toggle_minus.png differ diff --git a/doc/app/images/bullet_toggle_plus.png b/doc/app/images/bullet_toggle_plus.png new file mode 100644 index 0000000000..9ab4a89664 Binary files /dev/null and b/doc/app/images/bullet_toggle_plus.png differ diff --git a/doc/app/images/date.png b/doc/app/images/date.png new file mode 100644 index 0000000000..783c83357f Binary files /dev/null and b/doc/app/images/date.png differ diff --git a/doc/app/images/delete.png b/doc/app/images/delete.png new file mode 100644 index 0000000000..08f249365a Binary files /dev/null and b/doc/app/images/delete.png differ diff --git a/doc/app/images/find.png b/doc/app/images/find.png new file mode 100644 index 0000000000..1547479646 Binary files /dev/null and b/doc/app/images/find.png differ diff --git a/doc/app/images/loadingAnimation.gif b/doc/app/images/loadingAnimation.gif new file mode 100644 index 0000000000..82290f4833 Binary files /dev/null and b/doc/app/images/loadingAnimation.gif differ diff --git a/doc/app/images/macFFBgHack.png b/doc/app/images/macFFBgHack.png new file mode 100644 index 0000000000..c6473b324e Binary files /dev/null and b/doc/app/images/macFFBgHack.png differ diff --git a/doc/app/images/package.png b/doc/app/images/package.png new file mode 100644 index 0000000000..da3c2a2d74 Binary files /dev/null and b/doc/app/images/package.png differ diff --git a/doc/app/images/page_green.png b/doc/app/images/page_green.png new file mode 100644 index 0000000000..de8e003f9f Binary files /dev/null and b/doc/app/images/page_green.png differ diff --git a/doc/app/images/page_white_text.png b/doc/app/images/page_white_text.png new file mode 100644 index 0000000000..813f712f72 Binary files /dev/null and b/doc/app/images/page_white_text.png differ diff --git a/doc/app/images/page_white_width.png b/doc/app/images/page_white_width.png new file mode 100644 index 0000000000..1eb880947d Binary files /dev/null and b/doc/app/images/page_white_width.png differ diff --git a/doc/app/images/plugin.png b/doc/app/images/plugin.png new file mode 100644 index 0000000000..6187b15aec Binary files /dev/null and b/doc/app/images/plugin.png differ diff --git a/doc/app/images/ruby.png b/doc/app/images/ruby.png new file mode 100644 index 0000000000..f763a16880 Binary files /dev/null and b/doc/app/images/ruby.png differ diff --git a/doc/app/images/tag_blue.png b/doc/app/images/tag_blue.png new file mode 100644 index 0000000000..3f02b5f8f8 Binary files /dev/null and b/doc/app/images/tag_blue.png differ diff --git a/doc/app/images/tag_green.png b/doc/app/images/tag_green.png new file mode 100644 index 0000000000..83ec984bd7 Binary files /dev/null and b/doc/app/images/tag_green.png differ diff --git a/doc/app/images/transparent.png b/doc/app/images/transparent.png new file mode 100644 index 0000000000..d665e179ef Binary files /dev/null and b/doc/app/images/transparent.png differ diff --git a/doc/app/images/wrench.png b/doc/app/images/wrench.png new file mode 100644 index 0000000000..5c8213fef5 Binary files /dev/null and b/doc/app/images/wrench.png differ diff --git a/doc/app/images/wrench_orange.png b/doc/app/images/wrench_orange.png new file mode 100644 index 0000000000..565a9330e0 Binary files /dev/null and b/doc/app/images/wrench_orange.png differ diff --git a/doc/app/images/zoom.png b/doc/app/images/zoom.png new file mode 100644 index 0000000000..908612e394 Binary files /dev/null and b/doc/app/images/zoom.png differ diff --git a/doc/app/index.html b/doc/app/index.html new file mode 100644 index 0000000000..59cd4cba6b --- /dev/null +++ b/doc/app/index.html @@ -0,0 +1,343 @@ + + + + + + +Rails Application Documentation + + + + + + + + + + + + + + +
+

This is the API documentation for Rails Application Documentation. +

+ + + + + diff --git a/doc/app/js/darkfish.js b/doc/app/js/darkfish.js new file mode 100644 index 0000000000..b789a65631 --- /dev/null +++ b/doc/app/js/darkfish.js @@ -0,0 +1,161 @@ +/** + * + * Darkfish Page Functions + * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $ + * + * Author: Michael Granger + * + */ + +/* Provide console simulation for firebug-less environments */ +if (!("console" in window) || !("firebug" in console)) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", + "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; + + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +}; + + +/** + * Unwrap the first element that matches the given @expr@ from the targets and return them. + */ +$.fn.unwrap = function( expr ) { + return this.each( function() { + $(this).parents( expr ).eq( 0 ).after( this ).remove(); + }); +}; + + +function showSource( e ) { + var target = e.target; + var codeSections = $(target). + parents('.method-detail'). + find('.method-source-code'); + + $(target). + parents('.method-detail'). + find('.method-source-code'). + slideToggle(); +}; + +function hookSourceViews() { + $('.method-heading').click( showSource ); +}; + +function hookSearch() { + var input = $('#search-field').eq(0); + var result = $('#search-results').eq(0); + $(result).show(); + + var search_section = $('#search-section').get(0); + $(search_section).show(); + + var search = new Search(search_data, input, result); + + search.renderItem = function(result) { + var li = document.createElement('li'); + var html = ''; + + // TODO add relative path to + + + + + + + + + + +
+

Table of Contents - Rails Application Documentation

+ +

Pages

+ + +

Classes and Modules

+ + +

Methods

+ +
+ + + +