пятница, 25 июля 2014 г.

redmine ошибка в хроме

Не так давно мой любимый redmine поломался в Google Chrome. И оказался виноват в этом не я а Хром. Суть ошибки такова при попытке добавления файла (вложения - attacment)

Нашел bagfix достаточно быстро
http://www.redmine.org/issues/17151

http://www.redmine.org/attachments/12091/17151_redmine_2.3_latest.patch?utf8=%E2%9C%93&type=sbs

поправить руками можно так.
лезем на сервер в папку с редмайном.
затем открываем файл
public/javascripts/attachments.js
и на строке 118 сразу за строкой

 
function addInputFiles(inputEl) {

добавляем строку

 
 $(inputEl).attr('onchange', null);

затем на строке 136
сразу за строкой

 
 clearedFileInput.insertAfter('#attachments_fields');

добавляем строку

 
 clearedFileInput.attr('onchange', 'addInputFiles(this);');


У меня получилось так



суббота, 19 июля 2014 г.

написание плагинов для redmine перевод

Plugin-Tutorial

перевод руководства по созданию плагинов для Redmine

руководство по созданию плагинов Redmine

данное руководство рассчитано на Redmine 2.x. Руководство по созданию плагинов для Redmine 1.xздесь. Данное руководство предполагает что вы знакомы Ruby on Rails framework.

Создание новых плагинов

Рекомендуется установить переменную окружения RAILS_ENV используя команду ниже
$ export RAILS_ENV="production"
в Windows
$ export RAILS_ENV=production
Создать новый плагин вы можете используя генератор плагинов Redmine. Генератор плагинов Redmine имеет следующий синтаксис
ruby script/rails generate redmine_plugin <plugin_name>.
Итак откройте командную строку и перейдите в каталог redmine, затем выполните следующую команду:
$ ruby script/rails generate redmine_plugin Polls
      create  plugins/polls/app
      create  plugins/polls/app/controllers
      create  plugins/polls/app/helpers
      create  plugins/polls/app/models
      create  plugins/polls/app/views
      create  plugins/polls/db/migrate
      create  plugins/polls/lib/tasks
      create  plugins/polls/assets/images
      create  plugins/polls/assets/javascripts
      create  plugins/polls/assets/stylesheets
      create  plugins/polls/config/locales
      create  plugins/polls/test
      create  plugins/polls/README.rdoc
      create  plugins/polls/init.rb
      create  plugins/polls/config/routes.rb
      create  plugins/polls/config/locales/en.yml
      create  plugins/polls/test/test_helper.rb
Данная команда создала скелет вашего плагина в папке plugins/pools. Отредактируйте файл plugins/pools/init.rb и внесите туда необходимую информацию о плагине (название, Автор, описание, и версия)
Redmine::Plugin.register :polls do
  name 'Polls plugin'
  author 'John Smith'
  description 'A plugin for managing polls'
  version '0.0.1'
end
Перезапустите приложение и зайдите в браузере на страницу (http://localhost:3000/admin/plugins) После входа под профилем админа вы сможете увидеть новый плагин в списке плагинов новый плагин в списке плагинов
Примечание: любые изменения init.rb файл плагина требует перезапуска приложения, поскольку оно не перезагружает init.rb после каждого запроса на каждый запрос.

Генерация модели

Сейчас плагин не может сохранять никакую информацию. Давайте создадим простую модель опроса(Poll) для нашего плагина. Для создания модели используйте следующий синтаксис:
ruby script/rails generate redmine_plugin_model <plugin_name&gt <model_name> [field[:type][:index] field[:type][:index] ...]
выполним команду в командной строке
$ ruby script/rails generate redmine_plugin_model polls poll question:string yes:integer no:integer
      create  plugins/polls/app/models/poll.rb
      create  plugins/polls/test/unit/poll_test.rb
      create  plugins/polls/db/migrate/001_create_polls.rb
Это действие создаст модель Poll и соответствующий файл миграции file 001_create_polls.rb в plugins/polls/db/migrate:
class CreatePolls < ActiveRecord::Migration
  def change
    create_table :polls do |t|
      t.string :question
      t.integer :yes, :default => 0
      t.integer :no, :default => 0
    end
  end
end
Вы можете настроить ваш файл миграции (те. значения по умолчанию...) затем перенести базу данных с помощью следующей команды(прогнать миграцию):
$ rake redmine:plugins:migrate

Migrating polls (Polls plugin)...
==  CreatePolls: migrating ====================================================
-- create_table(:polls)
   -> 0.0410s
==  CreatePolls: migrated (0.0420s) ===========================================
Обратите внимание, что каждый модуль имеет свой собственный набор миграций.
Давайте добавим несколько опросов в консоли, так что нам было с чем работать. Консоль, где вы можете в интерактивном режиме работы и изучить Redmine среды и является очень информативной, чтобы поиграть. Но сейчас нам просто необходимо создать два Poll объекта
ruby script/rails console
[rails 3] rails console
>> Poll.create(:question => "Can you see this poll")
>> Poll.create(:question => "And can you see this other poll")
>> exit
Отредактируйте plugins/polls/app/models/poll.rb добавьте метод vote который будет вызываться из нашего контролера:
class Poll < ActiveRecord::Base
  def vote(answer)
    increment(answer == 'yes' ? :yes : :no)
  end
end

Генерация контролера

Сейчас плагин ничего не делает. Поэтому давайте создадим контроллер для него. Мы будем использовать генератор контролера для плагинов redmine. Со следующим синтаксисом:
ruby script/rails generate redmine_plugin_controller <plugin_name> <controller_name> [<actions>]
Выполните эту команду в консоле
$ ruby script/rails generate redmine_plugin_controller Polls polls index vote
      create  plugins/polls/app/controllers/polls_controller.rb
      create  plugins/polls/app/helpers/polls_helper.rb
      create  plugins/polls/test/functional/polls_controller_test.rb
      create  plugins/polls/app/views/polls/index.html.erb
      create  plugins/polls/app/views/polls/vote.html.erb
Это создаст контролер с двумя методами(actions)(#index и #vote). Отредактируйте файл plugins/polls/app/controllers/polls_controller.rb и внесите в два этих метода код необходимый для их работы
class PollsController  'index'
  end
end
Затем отредактируйте plugins/polls/app/views/polls/index.html.erb, который будет отображать существующие опросы:
<h2>Polls</h2>

<% @polls.each do |poll| %>
  <p>
  <%= poll.question %>?
  <%= link_to 'Yes', { :action => 'vote', :id => poll[:id], :answer => 'yes' }, :method => :post %> (<%= poll.yes %>) /
  <%= link_to 'No', { :action => 'vote', :id => poll[:id], :answer => 'no' }, :method => :post %> (<%= poll.no %>)
  </p>
<% end %>
Вы можете удалить плагины/polls/app/views/polls/vote.html.erb поскольку визуализация данного файла выполнятся не будет.

Добавление Роутинга(маршруты)

Redmine не поддерживает подстановки по умолчанию маршрут (':controller/:action/:id'). Плагины должны декларировать маршруты, по которым они нуждаются в файле config/routes.rb. Теперь отредактируйте plugins/polls/config/routes.rb и добавьте в него 2 маршрута для двух действий
get 'polls', :to => 'polls#index'
post 'post/:id/vote', :to => 'polls#vote'
вы можете найти больше информации о Роутинге в Rails здесь http://guides.rubyonrails.org/routing.htmlТеперь перезапустите ваше приложение и зайдите в браузере на страницу http://localhost:3000/polls. Вы должны увидеть 2 опроса и сможете проголосовать: Плагин для Redmine

интернационализация

Перевод файлы должны быть сохранены в config/locales, например. plugins/polls/config/locales/.

Добавление пункта меню принадлежащего плагину

Наш контроллер работает нормально, но пользователи должны знать url, чтобы увидеть опросы. С помощью Redmine plugin API, вы можете расширить стандартные меню(добавить в них свой пункт меню). Поэтому давайте добавим новый элемент в меню приложения.
Redmine::Plugin.register :redmine_polls do
  [...]

  menu :application_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls'
end
Синтаксис:
  menu(menu_name, item_name, url, options={})
Существует пять меню, которые можно расширить:
  • :top_menu - в верхнем левом меню
  • :account_menu - в верхнем правом рядом в ссылками войти зарегистрировать
  • :application_menu - главное меню отображается, когда пользователь находится не внутри проекта
  • :project_menu - главное меню отображается, когда пользователь находится внутри проекта
  • :admin_menu - меню отображается на странице администрирования (можете вставить после установки, прежде чем Plugins)
Доступные варианты:
  • :param - параметр ключ, используемый для проекта id (по умолчанию :id)
  • :if - Proc, которая вызывается перед отображением элемента, элемент отображается, только если она возвращает true,
  • :caption - меню заголовка, который может содержать:
    • локализованную строку Symbol (например :plugin_local_name)
    • строку
    • Proc, которые могут принять проект в качестве аргумента
  • :before, :after - место где в меню должен быть вставлен элемент (например. :after => :activity)
  • :first, :last - если установлено в true, то элемент будет встать в начало или в конец меню (например. :last => true)
  • :html - hash с html параметрами, передаваемые link_to при отображении пункта меню
В нашем примере мы добавили элемент в меню приложения, которая не содержит элементов по умолчанию. Перезапустите redmine и перейдите http://localhost:3000 http://www.redmine.org/attachments/download/854/application_menu.png
Теперь вы можете получить доступ к опросам, нажав на вкладке Polls с экрана приветствия.

Расширение меню проекта

Теперь, давайте рассмотрим, случай когда необходимо чтобы опросы задавались на уровне проекта (даже если это не так, в нашем примере).Мы хотели бы добавить Вкладку Polls в меню проекта, а не в меню приложения Откройте init.rb и замените строку, которую мы добавляли ранее ( menu :application_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls') на следующие две
Redmine::Plugin.register :redmine_polls do
  [...]

  permission :polls, { :polls => [:index, :vote] }, :public => true
  menu :project_menu, :polls, { :controller => 'polls', :action => 'index' }, :caption => 'Polls', :after => :activity, :param => :project_id
end
Вторая строка добавляет наши опросы вкладки в меню проекта, сразу после вкладки activity. Первая строка необходима и заявляет, что наши два метода из PollsController являются публичными. Мы вернемся позже, чтобы объяснить это более подробно. Перезапустить приложение и перейдите к одному из ваших проектов: http://www.redmine.org/attachments/download/3773/project_menu.png
Если вы щелкните на вкладке Polls(в 3-й позиции), то вы должны заметить, что меню проекта не отображается. Чтобы сделать проект меню видимой, вы должны инициализировать в контроллере инстансную переменную проекта (@project)
Для этого отредактируйте PollsController следующим образом
def index
  @project = Project.find(params[:project_id])
  @polls = Poll.find(:all) # @project.polls
end
id проекта доступна в param[:project_id] Теперь вы должны увидеть меню проекта находясь на вкладке Polls http://www.redmine.org/attachments/download/3774/project_menu_pools.png

Добавление новых прав

Сейчас любой желающий может проголосовать и посмотреть опросы. Давайте сделаем ее более гибкую настройку прав Мы собираемся создать 2 разрешения : одно для просмотра опросы и другая для голосования. Эти разрешения не публичные(опция :public => true удаляется). отредактируйте plugins/polls/init.rb и замените строчку с permission на две следующих
  permission :view_polls, :polls => :index
  permission :vote_polls, :polls => :vote
Перезапустите redmine и перейдите http://localhost:3000/roles/permissions: http://www.redmine.org/attachments/download/858/permissions1.png Теперь вы настраивать эти два разрешения для существующих ролей. Конечно, необходимо добавить код в PollsController который сделает эту защиту фактической в соответствии привилегиями текущего пользователя. Для этого нам всего лишь нужно добавить :authorize filter и сделать получение инстансной переменной @project возможной только после отработки данного фильтра Вот как это будет выглядеть для метода #index.
class PollsController  :index

  [...]

  def index
    @polls = Poll.find(:all) # @project.polls
  end

  [...]

  private

  def find_project
    # @project variable must be set before calling the authorize filter
    @project = Project.find(params[:project_id])
  end
end
Для метода vote данная проверка прав может быть сделана по аналогии После этого просмотр опросов и возможность голосовать будет доступна только админам и пользователям для ролей которых выставлены соответствующие разрешения
Если вы хотите ваши разрешения в на различных языках, вам нужно добавить необходимые текстовые метки в файле языка. Просто создайте файл соответствующий нужному языку *.yml (например. en.yml для английского) в папке plugins/polls/config/locales и внесите туда метки и перевод для них например как указано ниже
"en":
  permission_view_polls: View Polls
  permission_vote_polls: Vote Polls
В этом примере создается файл именем en.yml, но для всех остальных языков можно создать файлы аналогично. Как вы можете видеть на примере выше, метки соответствуют символам :view_polls и :vote_polls с дополнительным permission_.
Перезапустите redmine и укажите необходимые права

Создание модуля проекта

Теперь функции опроса доступны для всех ваших проектов.Но вы хотите иметь возможность включать ее только для некоторых проектов Итак, давайте создадим 'Polls' модуль проекта. Это делается путем оборачивания получение разрешений методом #project_module.
Отредактируйте init.rb и измените декларацию permissions(прав)
 project_module :polls do
    permission :view_polls, :polls => :index
    permission :vote_polls, :polls => :vote
  end
Перезапустите redmine и перейдите в настройки проекта Щелкнете не вкладке Modules. И вы сможете модуль Polls в списке модулей (выключенный по умолчанию) http://www.redmine.org/attachments/download/859/modules.png Теперь вы можете включать и выключать опросы для различных проектов

Улучшение внешнего вида проекта

Добавление стилей

Давайте начнем с добавления стилей для нашего плагина. Создайте файл с именем voting.css в каталоге plugins/polls/assets/stylesheets
    a.vote { font-size: 120%; }
    a.vote.yes { color: green; }
    a.vote.no  { color: red; }
При запуске приложения, файлы из файлопровода плагина (plugins/polls/assets) будут скопированы в public/plugin_assets/polls/ это необходимо чтобы сделать их доступными для вашего web-сервера. Поэтому любые изменения, таблицы стилей или javascripts в плагине требуют перезапуска Redmine. Используемые в стилях классы необходимо объявить в ссылках. для этого измените их в файле plugins/polls/app/views/polls/index.html.erb следующим образом
<%= link_to 'Yes', {:action => 'vote', :id => poll[:id], :answer => 'yes' }, :method => :post, :class => 'vote yes' %> (<%= poll.yes %>)
<%= link_to 'No', {:action => 'vote', :id => poll[:id], :answer => 'no' }, :method => :post, :class => 'vote no' %> (<%= poll.no %>)
Затем добавьте следующие строки в конце index.html.erb так, что ваша Таблица стилей может попасть в head страницы по Redmine:
<% content_for :header_tags do %>
    <%= stylesheet_link_tag 'voting', :plugin => 'polls' %>
<% end %>
Обратите внимание, что :plugin => 'polls' параметр требуется при вызове stylesheet_link_tag хелпера.
Скрипты могут быть включены в плагин представлений с использованием javascript_include_tag хелпера таким же образом.

Установка заголовка страницы

Вы можете задать title страницы внутри вашего представления с помощью html_title хелпера.
  <% html_title "Polls" %  >

Использование хуков(hooks)

Хуки в отображении

Хуки в отображениях в редмайне позволяют вставлять ваш контент в заранее определенные места в шаблонов. для примера посмотрите например код представленный по следующей ссылкеhttp://www.redmine.org/projects/redmine/repository/entry/tags/2.0.0/app/views/projects/show.html.erb#L52 вы можете увидеть два хука: первый имеет имя :view_projects_show_left и предназначен для вставки контента в левую часть шаблона и второй с именем :view_projects_show_right для вставки контента в правую часть шаблона.
Чтобы использовать один или несколько хуков в отображениях вы должны создать класс наследуемый от Redmine::Hook::ViewListener и реализующий методы хуков которые вы желаете использовать. Теперь чтобы выводить контент для определенных хуков на вкладке "обзор" в проектах вам вам необходимом подключить ваш класс в файле init.rb и реализовать методы с именами хуков которые хотите использовать.
Для нашего плагина создайте файл plugins/polls/lib/polls_hook_listener.rb и добавьте в него следующий код:
class PollsHookListener < Redmine::Hook::ViewListener
  def view_projects_show_left(context = {})
    return content_tag("p", "Custom content added to the left")
  end

  def view_projects_show_right(context = {})
    return content_tag("p", "Custom content added to the right")
  end
end
Также добавьте строчку в конец файла plugins/polls/init.rb:
require_dependency 'polls_hook_listener'
Перезапустите Redmine и перейдите на вкладку "обзор" проекта. Где вы сможете увидеть две наших строчки слева и справа.
Вы также можете использовать хелпер render_on для отображения частичных шаблонов. В нашем плагине замените содержимое файла plugins/polls/lib/polls_hook_listener.rb следующим:
class PollsHookListener  "polls/project_overview" 
end
Добавьте частичный шаблон в наш плагин для этого создайте файл app/views/polls/_project_overview.html.erb. Добавьте в него контент (Например "Это сообщение выведено с использованием хуков") который будет выведен в левой части вкладки "обзор" на странице проекта. Не забудьте перезапустить Redmine.

Хуки в контролерах

В работе

Создание настроек для вашего плагина

каждый плагин зарегистрированный в Redmine появляется на странице admin/plugins. Поддержка настроек осуществляется Settings controllerом. Данную фичу можно включить путем добавления метода "settings" в блок регистрирующий плагин в файле init.rb
Redmine::Plugin.register :redmine_polls do
  
  [ ... ]

  settings :default => {'empty' => true}, :partial => 'settings/poll_settings'
end
Добавление этого метода приведет к двум вещам. Во первых в блоке описания плагина добавится ссылка "Configure". Переход по которой приведет к странице созданной из частичного шаблона settings/poll_settings на которой будет распологаться ваши настройки. Во вторых появится возможность сохранять эти настройки в модуле плагина. Настройки будут сохранятся в виде хеша имя которого основанного на названии вашего плагина. Доступ к этому хешу можно получить при помощи объекта Setting передав в качестве метода plugin_<plugin name>. Например для нашего примера доступ к хешу можно получить вызвав Setting.plugin_redmine_polls. http://www.redmine.org/attachments/download/8962/plugin_with_config.pngОтображение которое будет загружено необходимо указать в параметре ключа :partial метода setting вызываемого при регистрации вашего плагина. Форма с настройками вашего плагина будет отображена внутри основного шаблона Redmine содержащего тег формы и кнопку для применения настроек. Параметры вашего плагина могут быть отображены при помощи стандартных элементов HTML форм.
http://www.redmine.org/attachments/download/8961/plugin_config_view.pngПредупреждение Если два плагина будут иметь одинаковые имя переданное в ключе :partial то настройки одного плагина перепишут настройки другого. По этому старайтесь придумать такие имена которые будут уникальны.
При формы с настройками, settings_controller будет принимать в качестве параметра хеш сформированный из вашей формы путем ее сериализации и сохранять в таком виде непосредственно в Setting.plugin_redmine_polls. Каждый раз при отображении страницы с вашими настройками значение Setting.plugin_redmine_polls будет содержать последние сохраненные настройки.
 
<table>
  <tbody>
    <tr>
      <th>Notification Default Address</th>
      <td><input type="text" id="settings_notification_default" 
                     value="<%= settings['notification_default'] %>" 
             name="settings[notification_default]" >
    </tr>
  </tbody>
</table>
В этом примере например для создания элементов формы конфигурации не используются Rails хелперы для форм. Это сделано по тому что мы не можем принимать параметров вида @settings только хеш. Form helpers будут пытаться получить доступ к атрибутам модели которой не существует. Например обращение к @settings.notification_default окончится неудачей так как его не существует и для обращения к данной опции следует использовать Setting.plugin_redmine_polls['notification_default'].
Наконец при указании ключа :default в методе settings при регистрации плагина можно будет указать значение которое будет возвращено Setting.plugin_redmine_polls в случаее если настройки еще не были установлены.

Тестирование вашего плагина

test/test_helper.rb

Вот содержание моего хелпер файла для тестов
require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper')

Пример теста

файл polls_controller_test.rb содержит следующий код:
require File.expand_path('../../test_helper', __FILE__)

class PollsControllerTest  1

    assert_response :success
    assert_template 'index'
  end
end

Выполнение теста

Инициализируйте базу данных " test", если это необходимо:
$ rake db:drop db:create db:migrate redmine:plugins:migrate redmine:load_default_data RAILS_ENV=test
выполните polls_controller_test.rb

Тестирование с учетом привилегий

Если ваш плагин требует наличие пользователя в проекте, то добавьте следующую строку в начале вашего функционального теста:
def test_index
  @request.session[:user_id] = 2
  ...
end
Если ваш плагин требуется специальное разрешение, необходимо добавить еще роль пользователя, например, так (укажите id ролей, которые подходят для пользователя):
def test_index
  Role.find(1).add_permission! :my_permission
  ...
end
Вы можете включить/отключить определенней модули следующим образом:
def test_index
  Project.find(1).enabled_module_names = [:mymodule]
  ...
end

четверг, 17 июля 2014 г.

аналог skype для веба

У меня на работе возникло задание сделать аналог skype для redmine.
и я было совсем упал духом но выход нашелся
http://peerjs.com/
понятно что технология еще очень сырая Stable (0.3.9)
и качество связи остовляет желать лучшего
но если всех пользователей crm пересадить на адекватные браузеры то все ок
http://cdn.peerjs.com/demo/videochat/

четверг, 10 июля 2014 г.

заменить title на h1

Из уст оптимизаторов часто звучит "Сгенерировать теги Title из h1". как это сделать тем более для очередного говно движка не понятно. А сделать нужно обязательно и быстро. Это значит пришло время костылей вот мой
function get_h1($base_url, $end_url, $param_name = "get_h1"){
 if (false !== strstr($end_url, "?")){
  $end_url .= "&".$param_name."=Y";
 }else{
  $end_url .= "?".$param_name."=Y";
 }
 if ("Y" == $_GET[$param_name]){
   return ;
 }
 $url = "http://".$base_url.$end_url;
 
 $c = file_get_contents($url);
 preg_match_all("/<[Hh]1.*>(.*)<\/[Hh]1/", $c, $m);
 if (!empty($m)){
   $title = "";
   foreach($m[1] as $k => $v){
  $title .= trim(strip_tags($v));
   }
   return $title;
 }
}
а в шаблоне
<?php echo  get_h1($_SERVER["HTTP_HOST"], $_SERVER["REQUEST_URI"]); ?>

PHP: The Right Way блог програмышки
Яндекс.Метрика