--- /dev/null
+= publications
+
+Description goes here
--- /dev/null
+
+class PublicationsController < ApplicationController
+ unloadable
+
+ @@source_file_field_id = 1
+
+ def issues
+ logger.info "Searching for issues with document name = " + params[:pub] + "."
+ joins = "JOIN issue_publications ON (issues.id = issue_publications.issue_id) JOIN publications ON (issue_publications.publication_id = publications.id)"
+
+ conditions = ['publications.source_file = ? ', params[:pub] ]
+ @issues = Issue.all(:joins => joins, :conditions => conditions)
+ respond_to do |format|
+ format.html
+ format.xml do
+ render :xml => @issues
+ end
+
+ format.json do
+ headers['Content-Type'] = 'application/json'
+ render :json => @issues
+ end
+ end
+ end
+
+ def redirect_to_platform
+ render :text => ""
+ end
+
+end
--- /dev/null
+module PublicationsHelper
+end
--- /dev/null
+class IssuePublication < ActiveRecord::Base
+ belongs_to :publication
+ belongs_to :issue
+end
--- /dev/null
+class Publication < ActiveRecord::Base
+ has_many :issues, :through => :issuepublications
+end
--- /dev/null
+<div>
+<p><label for="issue_source_files">Source File(s)</label>
+<input type='text'
+ id='issue_source_files' name="issue_source_files"
+ value='<%= @issue.source_files.join(' ') %>' />
+</div>
--- /dev/null
+<h2>Microrest#related-issues</h2>
+<%= @issues %>
+
+
--- /dev/null
+class CreatePublications < ActiveRecord::Migration
+ def self.up
+ create_table :publications do |t|
+ t.column :source_file, :string, :null => false
+ end
+ end
+
+ def self.down
+ drop_table :publications
+ end
+end
--- /dev/null
+class CreateIssuePublications < ActiveRecord::Migration
+ def self.up
+ create_table :issue_publications do |t|
+ t.column :publication_id, :integer, :null => false
+ t.column :issue_id, :intrger, :null => false
+ end
+ end
+
+ def self.down
+ drop_table :issue_publications
+ end
+end
--- /dev/null
+require 'redmine'
+
+# Patches to the Redmine core.
+require 'dispatcher'
+
+Dispatcher.to_prepare :redmine_kanban do
+ require_dependency 'issue'
+ # Guards against including the module multiple time (like in tests)
+ # and registering multiple callbacks
+ unless Issue.included_modules.include? RedminePublications::IssuePatch
+ Issue.send(:include, RedminePublications::IssuePatch)
+ end
+end
+
+require_dependency 'issue_publication_hook'
+
+Redmine::Plugin.register :redmine_publicatons do
+ name 'Publications managment plugin'
+ author 'Łukasz Rekucki'
+ description 'This plugn helps manage issues related to a publication.'
+ version '0.0.3'
+
+
+ requires_redmine :version_or_higher => '0.8.0'
+
+end
+
--- /dev/null
+# English strings go here
+my_label: "My label"
--- /dev/null
+# Provides a link to the document on the platform
+class IssuesPublicationHook < Redmine::Hook::ViewListener
+ def view_issues_show_details_bottom(context)
+ result = "<tr><td><b>Source File(s):</b></td><td>"
+ names = context[:issue].source_files.map {|name| "<span>" + name + "</span>"}
+ result << names.join(', ')
+ result + "</td></tr>"
+ end
+
+ def controller_issues_edit_before_save(context)
+ pub_field = context[:params][:issue_source_files]
+ context[:issue].source_files = pub_field
+ end
+
+ render_on :view_issues_form_details_bottom, :partial => 'issue_form_pub'
+end
--- /dev/null
+module RedminePublications
+ # Patches Redmine's Issues dynamically. Adds a +after_save+ filter.
+
+ module IssuePatch
+ def self.included(base) # :nodoc:
+ base.extend(ClassMethods)
+
+ base.send(:include, InstanceMethods)
+
+ # Same as typing in the class
+ base.class_eval do
+ unloadable # Send unloadable so it will not be unloaded in development
+
+ after_save :update_relations
+ # after_destroy :check_relations
+
+ # Add visible to Redmine 0.8.x
+ unless respond_to?(:visible)
+ named_scope :visible, lambda {|*args| { :include => :project,
+ :conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } }
+ end
+ end
+
+ end
+
+ module ClassMethods
+ end
+
+ module InstanceMethods
+ def source_files
+ if not @source_files
+ @source_files = self.lookup_source_files.map { |pub| pub.source_file }
+ end
+ @source_files
+ end
+
+ def source_files=(value)
+ @source_files = value
+ end
+
+ def lookup_source_files
+ Publication.all(
+ :joins =>
+ "JOIN issue_publications ON (issue_publications.publication_id = publications.id)",
+ :conditions =>
+ [" issue_publications.issue_id = ? ", self.id] )
+ end
+
+ def update_relations
+ self.reload
+ current_assocs = self.lookup_source_files
+ new_assocs_names = self.source_files.split(' ')
+
+ # delete unused relations
+ deleted = current_assocs.select { |v| not (new_assocs_names.include?(v.source_file)) }
+ deleted.each { |pub| IssuePublication.delete_all(
+ :contitions => ["issue_publications.issue_id = ? AND issue_publicatons.publication_id = ?",
+ self.id, pub.id]) }
+
+ new_assocs_names.each do |name|
+ pub = Publication.find_or_create_by_source_file(name)
+ IssuePublication.find_or_create_by_publication_id_and_issue_id(pub.id, self.id)
+ end
+
+ return true
+ end
+
+ end
+ end
+end
--- /dev/null
+connect 'publications/:pub',
+ :controller => 'publications',
+ :action => 'redirect_to_platform'
+
+connect 'publications/:pub/:action',
+ :controller => 'publications',
+ :format => 'html'
+
+connect 'publications/:pub/:action.:format',
+ :controller => 'publications'
--- /dev/null
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+one:
+ id: 1
+ source_file: One
+two:
+ id: 2
+ source_file: Two
--- /dev/null
+require File.dirname(__FILE__) + '/../test_helper'
+
+class MicrorestControllerTest < ActionController::TestCase
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
--- /dev/null
+# Load the normal Rails helper
+require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
+
+# Ensure that we are using the temporary fixture path
+Engines::Testing.set_fixture_path
--- /dev/null
+require File.dirname(__FILE__) + '/../test_helper'
+
+class PublicationTest < Test::Unit::TestCase
+ fixtures :publications
+
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end