Full Code of jfqd/redmine_helpdesk for AI

master 08468822690e cached
94 files
130.0 KB
46.8k tokens
124 symbols
1 requests
Download .txt
Repository: jfqd/redmine_helpdesk
Branch: master
Commit: 08468822690e
Files: 94
Total size: 130.0 KB

Directory structure:
gitextract_lz5v3in0/

├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── app/
│   └── views/
│       ├── _issue_edit.erb
│       └── _issue_history.erb
├── config/
│   └── locales/
│       ├── de.yml
│       ├── en.yml
│       ├── es.yml
│       ├── it.yml
│       ├── ja.yml
│       ├── pl.yml
│       ├── ru.yml
│       ├── tr.yml
│       └── zh.yml
├── db/
│   └── migrate/
│       ├── 001_create_custom_owner_email_field.rb
│       ├── 002_create_custom_fields_for_reply.rb
│       ├── 003_create_custom_field_for_sender_email.rb
│       ├── 004_create_custom_field_for_send_to_owner_default.rb
│       ├── 005_add_treat_as_supportclient_to_anonymous.rb
│       ├── 006_append_footer_to_first_reply.rb
│       ├── 007_create_custom_copy_to_field.rb
│       ├── 008_create_custom_field_cc_handling.rb
│       ├── 009_create_custom_field_for_reopen_closed_issues_by_email.rb
│       └── 010_create_custom_field_for_reply_separator.rb
├── init.rb
├── lib/
│   ├── helpdesk_hooks.rb
│   ├── helpdesk_mailer.rb
│   ├── macro_expander.rb
│   ├── redmine_helpdesk/
│   │   ├── journal_patch.rb
│   │   ├── mail_handler_patch.rb
│   │   └── mailer_patch.rb
│   └── tasks/
│       ├── local-db.rake
│       ├── plugin_ci.rake
│       └── redmine.rake
└── test/
    ├── confs/
    │   ├── database_mysql.yml
    │   ├── database_postgres.yml
    │   ├── database_postgres_ext.yml
    │   └── database_sqlite.yml
    ├── fixtures/
    │   ├── 2.6/
    │   │   ├── attachments.yml
    │   │   ├── custom_fields.yml
    │   │   ├── custom_fields_projects.yml
    │   │   ├── custom_fields_trackers.yml
    │   │   ├── custom_values.yml
    │   │   ├── enabled_modules.yml
    │   │   ├── enumerations.yml
    │   │   ├── issue_statuses.yml
    │   │   ├── issues.yml
    │   │   ├── journal_details.yml
    │   │   ├── journals.yml
    │   │   ├── member_roles.yml
    │   │   ├── members.yml
    │   │   ├── projects.yml
    │   │   ├── projects_trackers.yml
    │   │   ├── roles.yml
    │   │   ├── trackers.yml
    │   │   └── users.yml
    │   ├── 3.0/
    │   │   ├── attachments.yml
    │   │   ├── custom_fields.yml
    │   │   ├── custom_fields_projects.yml
    │   │   ├── custom_fields_trackers.yml
    │   │   ├── custom_values.yml
    │   │   ├── email_addresses.yml
    │   │   ├── enabled_modules.yml
    │   │   ├── enumerations.yml
    │   │   ├── issue_statuses.yml
    │   │   ├── issues.yml
    │   │   ├── journal_details.yml
    │   │   ├── journals.yml
    │   │   ├── member_roles.yml
    │   │   ├── members.yml
    │   │   ├── projects.yml
    │   │   ├── projects_trackers.yml
    │   │   ├── roles.yml
    │   │   ├── trackers.yml
    │   │   └── users.yml
    │   ├── files/
    │   │   └── 2006/
    │   │       └── 07/
    │   │           └── 060719210727_source.rb
    │   └── mail_handler/
    │       ├── ticket_by_unknown_user.eml
    │       ├── ticket_by_unknown_user_with_cc.eml
    │       ├── ticket_by_user_1.eml
    │       ├── ticket_by_user_2.eml
    │       ├── ticket_reply.eml
    │       ├── ticket_with_attachment.eml
    │       └── ticket_with_attributes.eml
    ├── functional/
    │   └── issues_controller_with_helpdesk_test.rb
    ├── test_helper.rb
    └── unit/
        ├── helpdesk_mailer_test.rb
        ├── journal_patch_test.rb
        ├── macro_expander_test.rb
        └── mail_handler_patch_test.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store
*~
test/app/*


================================================
FILE: .travis.yml
================================================
language: ruby
rvm:
- 2.5
- 2.6
- jruby
services:
  - mysql
  - postgresql
env:
  global:
  - REDMINE_LANG=en
  - MYSQL_DATABASE=redmine
  - MYSQL_HOST=127.0.0.1
  - MYSQL_PORT=3306
  - MYSQL_USER=root
  - MYSQL_PASSWORD=
  - POSTGRES_DATABASE=redmine
  - POSTGRES_USER=postgres
  matrix:
  - REDMINE_VERSION=4.0.5 DATABASE_ADAPTER=mysql
  - REDMINE_VERSION=4.0.5 DATABASE_ADAPTER=postgresql
matrix:
  allow_failures: # Incomplete ActiveRecord 4.2 support in jruby
  - rvm: 2.6
    env: REDMINE_VERSION=4.0.5 DATABASE_ADAPTER=mysql
  - rvm: 2.6
    env: REDMINE_VERSION=4.0.5 DATABASE_ADAPTER=postgresql
  - rvm: jruby
    env: REDMINE_VERSION=4.0.5 DATABASE_ADAPTER=mysql
  - rvm: jruby
    env: REDMINE_VERSION=4.0.5 DATABASE_ADAPTER=postgresql
addons:
  code_climate:
    repo_token:
      secure: "SAyz/KNRQQC1T2oGNUxbDceBcoaL/IxvEmeKEIR3iivj3RMJi2Nm8v5B2Su9MhQBegi2mH70ypgkTPmGh69tSONf1sqkkCAxsZnIqihl1Ai+dwM2KlBLGw/k+IG9/xD1+hgQiO06OKZMPO+Kj9X28mMqJ75YVKGE4alr1mfo2NM="
before_install:
  - rake helpdesk:redmine:install
  - cd test/app
  - export BUNDLE_GEMFILE=Gemfile
before_script:
  - echo $(pwd)
  - sudo service mysql start
  - echo $(ps -Af | grep mysqld)
  - export RAILS_ENV=test
  - mysql -e 'create database redmine;'
  - psql -c 'create database redmine;' -U postgres
  - bundle exec rake generate_secret_token
  - export RAILS_ENV=test
  - bundle exec rake db:migrate
script:
  - bundle exec rake helpdesk:ci


================================================
FILE: CHANGELOG.md
================================================
0.0.20
---
* Make plugin compatibility with Redmine 5.0.x

0.0.19
---
* Italian translation
* Fix logger and use new setting
* Do not send on private-notes
* Fix reopening closed issue error
* Improve de locale
* Fix typo in email_was_send_to_supportclient
* Sets To header optional
* Remove Gemfile.lock
* Find and process value of custom field directly
* Add X-Redmine-Issue-Tracker header to mailerpatch

0.0.18
---
* Remove batches as nobody has the time to fix the tests
* Remove untrue stuff from readme
* Update mail_handler_patch.rb
* Fix migration
* Incorrect issue and project ids usage
* Add space after the pre

0.0.17
---
* Fix issue by sending redmine journals with redmine_helpdesk
* Store email-details before each note by martincizek from orchitech
* Make option to reopen closed issues by email work
* Added support for reply separator by sandratatarevicova from orchitech

0.0.16
---
* Make plugin compatibility with Redmine 4.0.x
* Add option to reopen closed issues by email

0.0.15
---
* Added support for tracking email details by martincizek from orchitech

0.0.14
---
* Make plugin compatibility with Redmine 3.0.1 by Vilppu Vuorinen

0.0.13
---
* Unit and functional tests with travis and code climate support by Vilppu Vuorinen
* Add customizable email footers by martincizek
* Test compatibility with Redmine 2.6.2

0.0.12
---
* Add support for non-anonymous supportclients by martincizek
* Add issue matching based on standard MIME header references by martincizek
* Test compatibility with Redmine 2.5.3

0.0.11
---
* Make sure that the notes length is always calculated

0.0.10
---
* Fixed bug trying to send an email with empty notes

0.0.9
---
* Fixed non-working helpdesk-send-to-owner-default checkbox

0.0.8
---
* Add setting for handling send to owner default value by davidef

0.0.7
---
* Added reply-to header by barbazul

0.0.6
---
* Update code for redmine 2.4.x by Craig Gowing
* Minor compatibility issues fixed

0.0.5
---
* Fix skip validation issue 

0.0.4
---
* Update code for redmine 2.3.x
* Send any journal attachments with the email notification to the supportclient

0.0.3
---
* The sender email-address is now adjustable on a per project basis

0.0.2
---
* A standard first reply message can be send to the supportclient on ticket creation (optional, per project)
* The email-footer for the email notification to the supportclient can be adjusted (optional, per project)

0.0.1
---
* First release

================================================
FILE: CONTRIBUTING.md
================================================
# Issues

Please note that I cannot provide user support for this open source project. All issues related to user support will be closed without a further comment. Open source does not mean that I have unlimited time to solve problems of others for free!

If you need professional help please [contact me](http://www.qutic.com/support "hire a consultant") directly - I am for hire.

If you find a bug please create an issue in the tracker, write a patch and send me a pull request :-)


================================================
FILE: Gemfile
================================================
gem "codeclimate-test-reporter", group: :test, require: nil
unless (Gem::Specification::find_all_by_name('rake').any?)
  gem "rake", group: :test, require: nil
end


================================================
FILE: LICENSE
================================================
Copyright (c) 2012-2021 qutic development GmbH

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: README.md
================================================
# Redmine Helpdesk

Lightweight helpdesk plugin for redmine. Adds the email sender-address of an anonymous supportclient to the custom field 'owner-email' of a ticket which was created by a support email. Answers can be send to the supportclient by checking the support checkbox on a journal.

## Support

You want to support the development of this plugin? [We provide Redmine hosting including the Helpdesk plugin](https://qutic.com/de/loesungen/redmine-hosting/).

## Features

* No need to create any user accounts for anonymous user
* Support for sending an email notification to the (anonymous user) supportclient on ticket creation
* A standard first reply message can be send to the supportclient on ticket creation (optional, per project)
* The email-footer for the email notification to the supportclient can be adjusted (optional, per project)
* The email-footer can be customized by using the following placeholders: 
  - Issue parameters
    - ##issue-id##
    - ##issue-subject##
    - ##issue-tracker##
    - ##issue-status##
  - Project parameters
    - ##project-name##
  - User parameters
    - ##user-name## 
    - ##user-firstname##
    - ##user-lastname##
    - ##user-mail##
    - ##user-login##
    - all user custom fields: ##user-cf-[user's custom field name]##, e.g. ##user-cf-position##
  - Base parameters
    - ##time-now##
* The sender email-address can be adjusted (optional, per project)
* Internal communication is not send to the supportclient
* The supportclient will get an email notification if the support checkbox on the journal is checked (default value is optional)
* Journal attachments will be delivered too
* Cc header is handled if the cc-handling checkbox is checked. (optional, per project)
* Reopening a closed issue is handled if the reopen-closed-issues-by-email checkbox is checked. (optional, per project)

## Screenshot

![Send mail to supportclient](doc/send-mail-to-supportclient.jpg "New checkbox 'Send mail to supportclient'")

## Getting the plugin

A copy of the plugin can be downloaded from [GitHub](https://github.com/jfqd/redmine_helpdesk)

## Installation

To install the plugin clone the repo from github and migrate the database:

```
cd /path/to/redmine/
git clone git://github.com/jfqd/redmine_helpdesk.git plugins/redmine_helpdesk
bundle install --without development test rmagick
bundle exec rake redmine:plugins:migrate RAILS_ENV=production
```

To uninstall the plugin migrate the database back and remove the plugin:

```
cd /path/to/redmine/
rake redmine:plugins:migrate NAME=redmine_helpdesk VERSION=0 RAILS_ENV=production
rm -rf plugins/redmine_helpdesk
```

Further information about plugin installation can be found at: https://www.redmine.org/wiki/redmine/Plugins

## Usage

To use the helpdesk functionality you need to

* add the custom field 'owner-email' to a project in the project configuration
* add a standard first reply message into the custom_field 'helpdesk-first-reply' in the project configuration (optional)
* add an email-footer into the custom_field 'helpdesk-email-footer' in the project configuration
* add a sender email address into the custom_field 'helpdesk-sender-email' in the project configuration (optional)
* make sure 'Issue added' and 'Issue updated' in the general redmine settings for email notifications are checked
* add the permission 'Treat as supportclient' to all roles you want to be treated as supportclient (the permission is automatically added to the 'Anonymous' role)
* disable standard notifications for non-anonymous supportclients to prevent their spamming (optional)
* add a cronjob for creating issues from support emails

![project configuration sample](doc/project-settings.jpg "Per project configuration sample")

## Cronjob

Creating tickets from support emails through an IMAP-account is done by a cronjob. If you are not familiar with cron you first should read about the concept. The following syntax is for ubuntu or debian linux:

```
*/5 * * * * redmineuser /path/to/your/rake -f /path/to/redmine/Rakefile --silent redmine:email:receive_imap RAILS_ENV="production" host=mail.example.com port=993 username=username password=password ssl=true project=project_identifier folder=INBOX move_on_success=processed move_on_failure=failed no_permission_check=1 unknown_user=accept 1 > /dev/null
```

Further information about receiving emails with redmine can be found at: [https://www.redmine.org/projects/redmine/wiki/RedmineReceivingEmails](https://www.redmine.org/projects/redmine/wiki/RedmineReceivingEmails#Fetching-emails-from-an-IMAP-server)

Please note that forwarding emails with **rdm-mailhandler.rb** is currently **not supported** by the plugin.

## Compatibility

The latest version of this plugin is only compatible with Redmine 5.0, 5.1.

* A version for Redmine 4.2.x is tagged with [v4.2](https://github.com/jfqd/redmine_helpdesk/releases/tag/v4.2 "plugin version for Redmine 4.2.x") and available for [download on github](https://github.com/jfqd/redmine_helpdesk/archive/v4.2.zip "download plugin for Redmine 4.2.x").
* A version for Redmine 4.0.x is tagged with [v4.0](https://github.com/jfqd/redmine_helpdesk/releases/tag/v4.0 "plugin version for Redmine 4.0.x") and available for [download on github](https://github.com/jfqd/redmine_helpdesk/archive/v4.0.zip "download plugin for Redmine 4.0.x").
* A version for Redmine 3.0.x and 3.1.x is tagged with [v3.1](https://github.com/jfqd/redmine_helpdesk/releases/tag/v3.1 "plugin version for Redmine 3.0.x and 3.1.x") and available for [download on github](https://github.com/jfqd/redmine_helpdesk/archive/v3.1.zip "download plugin for Redmine 3.0.x and 3.1.x").
* A version for Redmine 2.4.x and 2.5.x is tagged with [v2.5](https://github.com/jfqd/redmine_helpdesk/releases/tag/v2.5 "plugin version for Redmine 2.4.x and 2.5.x") and available for [download on github](https://github.com/jfqd/redmine_helpdesk/archive/v2.5.zip "download plugin for Redmine 2.4.x and 2.5.x").
* A version for Redmine 2.3.x is tagged with [v2.3](https://github.com/jfqd/redmine_helpdesk/tree/v2.3 "plugin version for Redmine 2.3.x") and available for [download on github](https://github.com/jfqd/redmine_helpdesk/archive/v2.3.zip "download plugin for Redmine 2.3.x").
* A version for Redmine 1.2.x. up to 1.4.7. is tagged with [v1.4](https://github.com/jfqd/redmine_helpdesk/tree/v1.4 "plugin version for Redmine 1.2.x up to 1.4.7") and available for [download on github](https://github.com/jfqd/redmine_helpdesk/archive/v1.4.zip "download plugin for Redmine 1.2.x up to 1.4.7").

If you prefer to run Redmine with JRuby make sure to use Redmine versions prior to 3.0.x!

## Development

### Testing

Rake tasks for testing against Redmine are provided. Redmine is installed under `test/app` and tests are run against the local instance.

```bash
REDMINE_VERSION=3.2 DATABASE_ADAPTER=mysql rake helpdesk:redmine:install
```

Docker is used to provide local MySQL (`DATABASE_ADAPTER=mysql`) and PostgreSQL (`DATABASE_ADAPTER=postgresql_ext`) instances.

```bash
export DATABASE_ADAPTER=mysql
rake helpdesk:prepare_local
rake helpdesk:migrate
```

Test suite can be executed with:

```bash
DATABASE_ADAPTER=mysql rake helpdesk:ext_ci
```

The local database instance has to be stopped with a rake task:

```bash
rake helpdesk:localdb:stop
```

## Contributions

* [MatthiasPetermann](https://github.com/MatthiasPetermann) - Update for compatibility with Redmine 5.x / Rails 6.x
* [rrsach](https://github.com/rrsach) - Redmine 5 Compatibility
* [gianpaol0](https://github.com/gianpaol0) - italian translation
* [mgeerdsen](https://github.com/mgeerdsen) - Fix reopening closed issue error
* [mgeerdsen](https://github.com/mgeerdsen) - Improve de locale
* [lmorillas](https://github.com/lmorillas) - Fix Error when message hasn't "To:" header
* [promasu](https://github.com/promasu) - Add X-Redmine-Issue-Tracker header to mailerpatch
* [ANemcov](https://github.com/ANemcov) - incorrect issue and project ids usage
* [ismaelgc](https://github.com/ismaelgc) - Spanish translation
* [monaka](https://github.com/monaka) - Japanese translation
* [avoidik](https://github.com/avoidik) - Add missed Russian translation into roles and access manager
* [WhereIsPedro](https://github.com/WhereIsPedro) - Polish translation
* [vilppuvuorinen](https://github.com/vilppuvuorinen) - 3.0.x compatibility
* [vilppuvuorinen](https://github.com/vilppuvuorinen) - Unit and functional tests with travis and code climate support
* [ssidelnikov](https://github.com/ssidelnikov) - Make sure that the notes length is always calculated
* [nifuki](https://github.com/nifuki) - Fixed bug trying to send an email with empty notes
* [nifuki](https://github.com/nifuki) - Fixed non-working helpdesk-send-to-owner-default checkbox
* [box789](https://github.com/box789) - Russian translation
* [seqizz](https://github.com/seqizz) - Turkish translation
* [benstwa](https://github.com/benstwa) - 'send' should be 'sent'
* [davidef](https://github.com/davidef) - Add setting for handling sent to owner default value
* [Craig Gowing](https://github.com/craiggowing) - Redmine 2.4 compatibility
* [Barbazul](https://github.com/barbazul) - Added reply-to header
* [Orchitech Solutions](https://github.com/orchitech) - Added issue matching based on standard MIME header references
* [Orchitech Solutions](https://github.com/orchitech) - Added support for non-anonymous supportclients (sponsored by ISIC Global Office)
* [Orchitech Solutions](https://github.com/orchitech) - Added support for customizable email footers (sponsored by ISIC Global Office)
* [Orchitech Solutions](https://github.com/orchitech) - Added support for tracking email details (sponsored by ISIC Global Office)
* [shackijj](https://github.com/shackijj) - Added Cc header handling
* [archonwang](https://github.com/archonwang) - Add Simplified Chinese
* [Niremizov](https://github.com/Niremizov) - Set owner email only if it wasn't set before
* [ghost](https://github.com/ghost) - Fix attachements truncated in email sent to supportclient
* [Orchitech Solutions](https://github.com/orchitech) - Added support for reply separator (sponsored by ISIC Global Office)

## License

This plugin is licensed under the MIT license. See LICENSE-file for details.

## Copyright

Copyright (c) 2012-2022 qutic development GmbH


================================================
FILE: Rakefile
================================================
Dir.glob('lib/tasks/*.rake').each { |r| load r}


================================================
FILE: app/views/_issue_edit.erb
================================================
<%= check_box_tag('send_to_owner', "true", (send_to_owner_default == "1")) %> <%=h t('label_support_checkbox') %> (<%=h email %>)


================================================
FILE: app/views/_issue_history.erb
================================================
<i style="display:block;margin-bottom:10px;"><%=h t('email_was_send_to_supportclient') %></i>

================================================
FILE: config/locales/de.yml
================================================
de:
  label_support_checkbox: "E-Mail an Support-Anfragenden senden"
  email_was_send_to_supportclient: "Diese Antwort wurde an den Support-Anfragenden gesendet."
  permission_treat_user_as_supportclient: "Nutzer als Support-Anfragenden behandeln"

================================================
FILE: config/locales/en.yml
================================================
en:
  label_support_checkbox: "Send mail to supportclient"
  email_was_send_to_supportclient: "This answer was sent to the supportclient."


================================================
FILE: config/locales/es.yml
================================================
es:
  label_support_checkbox: "Enviar correo al usuario de soporte"
  email_was_send_to_supportclient: "Esta respuesta ha sido enviada al usuario de soporte."


================================================
FILE: config/locales/it.yml
================================================
it:
  label_support_checkbox: "Invia email al cliente"
  email_was_send_to_supportclient: "Questa risposta è stata inviata al cliente."


================================================
FILE: config/locales/ja.yml
================================================
ja:
  label_support_checkbox: "サポート顧客へメールを送信"
  email_was_send_to_supportclient: "この回答はサポート顧客へ送信されました。"


================================================
FILE: config/locales/pl.yml
================================================
pl:
  label_support_checkbox: "Wyślij wiadomość do klienta"
  email_was_send_to_supportclient: "Wiadomość została wysłana do klienta."


================================================
FILE: config/locales/ru.yml
================================================
ru:
  label_support_checkbox: "Отправить e-mail клиенту поддержки"
  email_was_send_to_supportclient: "Этот ответ был отправлен клиенту поддержки"
  permission_treat_user_as_supportclient: "Определять пользователя как клиента техподдержки"  


================================================
FILE: config/locales/tr.yml
================================================
tr:
  label_support_checkbox: "Bu yanıtı destek isteyen müşteriye e-posta ile gönder"
  email_was_send_to_supportclient: "Bu yanıt destek talebi isteyen müşteriye de gönderildi."



================================================
FILE: config/locales/zh.yml
================================================
zh:
  label_support_checkbox: "发送反馈Email至客户"
  email_was_send_to_supportclient: "反馈邮件已发送至客户。"
  permission_treat_user_as_supportclient: "将用户作为客户"  


================================================
FILE: db/migrate/001_create_custom_owner_email_field.rb
================================================
class CreateCustomOwnerEmailField < ActiveRecord::Migration[5.2]
  def self.up
    # fix PG:DuplicateColumn errors
    # https://github.com/jfqd/redmine_helpdesk/issues/66
    unless column_exists? :journals, :send_to_owner
      add_column :journals, :send_to_owner, :boolean, :default => false
      c = CustomField.new(
        :name => 'owner-email',
        :editable => true,
        :field_format => 'string')
      c.type = 'IssueCustomField' # cannot be set by mass assignement!
      c.save
      Tracker.all.each do |t|
        execute "INSERT INTO custom_fields_trackers (custom_field_id,tracker_id) VALUES (#{c.id},#{t.id})"
      end
    end
  end

  def self.down
    c = CustomField.find_by_name('owner-email')
    execute "DELETE FROM custom_fields_trackers WHERE custom_field_id=#{c.id}"
    c.delete
    remove_column :journals, :send_to_owner
  end
end


================================================
FILE: db/migrate/002_create_custom_fields_for_reply.rb
================================================
class CreateCustomFieldsForReply < ActiveRecord::Migration[5.2]
  def self.up
    c = CustomField.new(
      :name => 'helpdesk-first-reply',
      :editable => true,
      :visible => false,          # do not show it on the project summary page
      :field_format => 'text')
    c.type = 'ProjectCustomField' # cannot be set by mass assignement!
    c.save
    d = CustomField.new(
      :name => 'helpdesk-email-footer',
      :editable => true,
      :visible => false,          # do not show it on the project summary page
      :field_format => 'text')
    d.type = 'ProjectCustomField' # cannot be set by mass assignement!
    d.save
  end

  def self.down
    CustomField.find_by_name('helpdesk-first-reply').delete
    CustomField.find_by_name('helpdesk-email-footer').delete
  end
end

================================================
FILE: db/migrate/003_create_custom_field_for_sender_email.rb
================================================
class CreateCustomFieldForSenderEmail < ActiveRecord::Migration[5.2]
  def self.up
    c = CustomField.new(
      :name => 'helpdesk-sender-email',
      :editable => true,
      :visible => true,
      :field_format => 'string')
    c.type = 'ProjectCustomField' # cannot be set by mass assignement!
    c.save
  end

  def self.down
    CustomField.find_by_name('helpdesk-sender-email').delete
  end
end

================================================
FILE: db/migrate/004_create_custom_field_for_send_to_owner_default.rb
================================================
class CreateCustomFieldForSendToOwnerDefault < ActiveRecord::Migration[5.2]
  def self.up
    c = CustomField.new(
      :name => 'helpdesk-send-to-owner-default',
      :editable => true,
      :visible => false,          # do not show it on the project summary page
      :field_format => 'bool')
    c.type = 'ProjectCustomField' # cannot be set by mass assignement!
    c.save
  end

  def self.down
    CustomField.find_by_name('helpdesk-send-to-owner-default').delete
  end
end


================================================
FILE: db/migrate/005_add_treat_as_supportclient_to_anonymous.rb
================================================
class AddTreatAsSupportclientToAnonymous < ActiveRecord::Migration[5.2]
  def self.up
    anon_id = User.where(type: 'AnonymousUser').first.try(:id) ||
              User.where('lastname LIKE ?', 'Anonymous').first.try(:id) ||
              4
    role = Role.where(builtin: anon_id).first
    role.add_permission!(:treat_user_as_supportclient) unless role.nil?
  end

  def self.down
    Role.all.each do |r|
      r.remove_permission!(:treat_user_as_supportclient)
    end
  end
end


================================================
FILE: db/migrate/006_append_footer_to_first_reply.rb
================================================
class AppendFooterToFirstReply < ActiveRecord::Migration[5.2]

  # Appends helpdesk-email-footer to helpdesk-first-reply to ensure backward
  # compatibility for updaters. See https://github.com/jfqd/redmine_helpdesk/issues/52
  def self.up
    first_reply_cf_id = CustomField.find_by_name('helpdesk-first-reply').id
    footer_cf_id = CustomField.find_by_name('helpdesk-email-footer').id

    CustomValue.where(:custom_field_id => first_reply_cf_id).each do |first_reply_cv|
      if !first_reply_cv.value.nil?
        first_reply_with_footer = first_reply_cv.value
        first_reply_with_footer << "\n\n"
        first_reply_with_footer << CustomValue.where("custom_field_id=? and customized_id=?", footer_cf_id, first_reply_cv.customized_id).first.value

        CustomValue.update(first_reply_cv.id, :value => first_reply_with_footer)
      end
    end
  end

end


================================================
FILE: db/migrate/007_create_custom_copy_to_field.rb
================================================
class CreateCustomCopyToField < ActiveRecord::Migration[5.2]
  def self.up
    c = CustomField.new(
      :name => 'copy-to',
      :editable => true,
      :field_format => 'string')
    c.type = 'IssueCustomField' # cannot be set by mass assignement!
    c.save
    Tracker.all.each do |t|
      execute "INSERT INTO custom_fields_trackers (custom_field_id,tracker_id) VALUES (#{c.id},#{t.id})"
    end
  end

  def self.down
    c = CustomField.find_by_name('copy-to')
    execute "DELETE FROM custom_fields_trackers WHERE custom_field_id=#{c.id}"
    c.delete
  end
end


================================================
FILE: db/migrate/008_create_custom_field_cc_handling.rb
================================================
class CreateCustomFieldCcHandling < ActiveRecord::Migration[5.2]
  def self.up
    c = CustomField.new(
      :name => 'cc-handling',
      :editable => true,
      :visible => true,
      :field_format => 'bool')
    c.type = 'ProjectCustomField' # cannot be set by mass assignement!
    c.save
  end

  def self.down
    CustomField.find_by_name('cc-handling').delete
  end
end


================================================
FILE: db/migrate/009_create_custom_field_for_reopen_closed_issues_by_email.rb
================================================
class CreateCustomFieldForReopenClosedIssuesByEmail < ActiveRecord::Migration[5.2]
  def self.up
    c = CustomField.new(
      :name => 'reopen-issues-with',
      :editable => true,
      :visible => true,
      :field_format => 'string')
    c.type = 'ProjectCustomField' # cannot be set by mass assignement!
    c.save
  end

  def self.down
    CustomField.find_by_name('reopen-issues-with').delete
  end
end

================================================
FILE: db/migrate/010_create_custom_field_for_reply_separator.rb
================================================
class CreateCustomFieldForReplySeparator < ActiveRecord::Migration[5.2]
  def self.up
    begin
      c = CustomField.new(
        :name => 'helpdesk-reply-separator',
        :editable => true,
        :visible => false,          # do not show it on the project summary page
        :field_format => 'string',
        :default_value => '-- Reply above this line --')
      c.type = 'ProjectCustomField'
      c.save
    rescue
      # rescue a possible migration error caused by renumbering the file
    end
  end

  def self.down
    CustomField.find_by_name('helpdesk-reply-separator').delete
  end
end

================================================
FILE: init.rb
================================================
require 'redmine'
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/lib"
require 'helpdesk_hooks'
require 'helpdesk_mailer'
require 'redmine_helpdesk/journal_patch'
require 'redmine_helpdesk/mail_handler_patch'
require 'redmine_helpdesk/mailer_patch'

Redmine::Plugin.register :redmine_helpdesk do
  name 'Redmine helpdesk plugin'
  author 'Stefan Husch'
  description 'Redmine helpdesk plugin'
  version '0.0.20'
  requires_redmine :version_or_higher => '5.0.0'
  project_module :issue_tracking do
    permission :treat_user_as_supportclient, {}
  end
end


================================================
FILE: lib/helpdesk_hooks.rb
================================================
class HelpdeskHooks < Redmine::Hook::Listener
  
  # render partial for 'Send mail to supportclient'
  def view_issues_edit_notes_bottom(context={})
    i = Issue.find(context[:issue].id)
    c = CustomField.find_by_name('owner-email')
    owner_email = i.custom_value_for(c).try(:value)
    return if owner_email.blank?
    p = i.project
    s = CustomField.find_by_name('helpdesk-send-to-owner-default')
    send_to_owner_default = p.custom_value_for(s).try(:value) if p.present? && s.present?
    lookup   = ActionView::LookupContext.new(File.dirname(__FILE__) + '/../app/views/')
    context  = ActionView::Base.with_empty_template_cache.new(lookup, {}, nil)
    renderer = ActionView::Renderer.new(lookup)
    renderer.render(
      context,
      partial: "issue_edit",
      locals: {
        email: owner_email,
        send_to_owner_default: (send_to_owner_default.present? && send_to_owner_default || false)
      }
    )
  end
  
  # fetch 'send_to_owner' param and set the value into journal.send_to_owner
  def controller_issues_edit_before_save(context={})
    send_to_owner = (context[:params]['send_to_owner'] == "true")
    context[:journal].send_to_owner = send_to_owner
  end
  
  # add a history note on the journal
  def view_issues_history_journal_bottom(context={})
    return if (context[:journal].nil? || context[:journal].notes.nil? || context[:journal].notes.length == 0)
    return unless context[:journal].send_to_owner == true
    i = Issue.find(context[:journal].journalized_id)
    c = CustomField.find_by_name('owner-email')
    owner_email = i.custom_value_for(c).try(:value)
    return if owner_email.blank?
    lookup   = ActionView::LookupContext.new(File.dirname(__FILE__) + '/../app/views/')
    context  = ActionView::Base.with_empty_template_cache.new(lookup, {}, nil)
    renderer = ActionView::Renderer.new(lookup)
    renderer.render(
      context,
      partial: "issue_history",
      locals: {
        email: owner_email
      }
    )
  end
  
end


================================================
FILE: lib/helpdesk_mailer.rb
================================================
#
# With Rails 3 mail is send with the mail method. Sadly redmine
# uses this method-name too in their mailer. This is the reason
# why we need our own Mailer class.
#
class HelpdeskMailer < ActionMailer::Base
  helper :application

  include Redmine::I18n
  include MacroExpander

  # set the hostname for url_for helper
  def self.default_url_options
    { :host => Setting.host_name, :protocol => Setting.protocol }
  end

  # Sending email notifications to the supportclient
  def email_to_supportclient(issue, params)
    # issue, recipient, journal=nil, text='', copy_to=nil

    recipient = params[:recipient]
    journal = params[:journal]
    text = params[:text]
    carbon_copy = params[:carbon_copy]

    redmine_headers 'Project' => issue.project.identifier,
                    'Issue-Id' => issue.id,
                    'Issue-Author' => issue.author.login
    redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
    message_id issue
    references issue

    subject = "[#{issue.project.name} - ##{issue.id}] #{issue.subject}"
    # Set 'from' email-address to 'helpdesk-sender-email' if available.
    # Falls back to regular redmine behaviour if 'sender' is empty.
    p = issue.project
    s = CustomField.find_by_name('helpdesk-sender-email')
    sender = p.custom_value_for(s).try(:value) if p.present? && s.present?
    # If a custom field with text for the first reply is
    # available then use this one instead of the regular
    r = CustomField.find_by_name('helpdesk-first-reply')
    f = CustomField.find_by_name('helpdesk-email-footer')
    reply  = p.nil? || r.nil? ? '' : p.custom_value_for(r).try(:value)
    footer = p.nil? || f.nil? ? '' : p.custom_value_for(f).try(:value)
    # add carbon copy
    ct = CustomField.find_by_name('copy-to')
    if carbon_copy.nil?
      carbon_copy = issue.custom_value_for(ct).try(:value)
    end
    # add any attachements
    if journal.present? && text.present?
      journal.details.each do |d|
        if d.property == 'attachment'
          a = Attachment.find(d.prop_key)
          begin
            attachments[a.filename] = File.binread(a.diskfile)
          rescue
            # ignore rescue
          end
        end
      end
    end
    if @message_id_object
      headers[:message_id] = "<#{self.class.message_id_for(@message_id_object)}>"
    end
    if @references_objects
      headers[:references] = @references_objects.collect {|o| "<#{self.class.references_for(o)}>"}.join(' ')
    end
    # create mail object to deliver
    mail = if text.present? || reply.present?
      # sending out the journal note to the support client
      # or the first reply message
      t = text.present? ? "#{text}\n\n#{footer}" : reply
      body = expand_macros(t, issue, journal)

      # precess reply-separator
      f = CustomField.find_by_name('helpdesk-reply-separator')
      reply_separator = issue.project.custom_value_for(f).try(:value)
      if !reply_separator.blank?
        body = reply_separator + "\n\n" + body
      end

      mail(
        :from     => sender.present? && sender || Setting.mail_from,
        :reply_to => sender.present? && sender || Setting.mail_from,
        :to       => recipient,
        :subject  => subject,
        :body     => body,
        :date     => Time.zone.now,
        :cc       => carbon_copy
      )
    else
      # fallback to a regular notifications email with redmine view
      @issue = issue
      @journal = journal
      @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue)
      mail(
        :from     => sender.present? && sender || Setting.mail_from,
        :reply_to => sender.present? && sender || Setting.mail_from,
        :to       => recipient,
        :subject  => subject,
        :date     => Time.zone.now,
        :template_path => 'mailer',
        :template_name => 'issue_edit',
        :cc            => carbon_copy
      )
    end
    # return mail object to deliver it
    return mail
  end

  private

  # Appends a Redmine header field (name is prepended with 'X-Redmine-')
  def redmine_headers(h)
    h.each { |k,v| headers["X-Redmine-#{k}"] = v.to_s }
  end

  def self.token_for(object, rand=true)
    timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
    hash = [
      "redmine",
      "#{object.class.name.demodulize.underscore}-#{object.id}",
      timestamp.strftime("%Y%m%d%H%M%S")
    ]
    if rand
      hash << Redmine::Utils.random_hex(8)
    end
    host = Setting.mail_from.to_s.strip.gsub(%r{^.*@|>}, '')
    host = "#{::Socket.gethostname}.redmine" if host.empty?
    "#{hash.join('.')}@#{host}"
  end

  # Returns a Message-Id for the given object
  def self.message_id_for(object)
    token_for(object, true)
  end

  # Returns a uniq token for a given object referenced by all notifications
  # related to this object
  def self.references_for(object)
    token_for(object, false)
  end

  def message_id(object)
    @message_id_object = object
  end

  def references(object)
    @references_objects ||= []
    @references_objects << object
  end
end


================================================
FILE: lib/macro_expander.rb
================================================
module MacroExpander
  def expand_macros(string, issue, journal)
    e = Expander.new(string, issue, journal)
    e.expand
  end

  class Expander
    include Redmine::I18n

    def initialize(string, issue, journal)
      @string = string
      @issue = issue
      @journal = journal
    end

    def expand
      unless @issue.nil?
        expand_issue
        expand_project
      end
      expand_user unless @journal.nil?
      expand_base

      @string
    end

    private

    def expand_issue
      @string.gsub!("##issue-id##", @issue.id.to_s)
      @string.gsub!("##issue-subject##", @issue.subject)
      @string.gsub!("##issue-tracker##", @issue.tracker.name)
      @string.gsub!("##issue-status##", @issue.status.name)
    end

    def expand_project
      p = @issue.project
      @string.gsub!("##project-name##", p.name)
    end

    def expand_user
      u = @journal.user
      @string.gsub!("##user-name##", u.name)
      @string.gsub!("##user-firstname##", u.firstname)
      @string.gsub!("##user-lastname##", u.lastname)
      @string.gsub!("##user-mail##", u.mail)
      @string.gsub!("##user-login##", u.login)
      expand_user_cf(u)
    end

    def expand_user_cf(user)
      CustomField.where(
        "type = 'UserCustomField'").each do |user_cf|
        cf_name = user_cf.name.downcase.gsub(' ', '-')
        user_cf_cv = user.custom_value_for(user_cf).try(:value)
        @string.gsub!("##user-cf-#{cf_name}##", user_cf_cv) unless user_cf_cv.nil?
      end
    end

    def expand_base
      @string.gsub!("##time-now##", I18n.l(Time.zone.now))
    end
  end
end


================================================
FILE: lib/redmine_helpdesk/journal_patch.rb
================================================
module RedmineHelpdesk
  module JournalPatch
    def self.included(base) # :nodoc:
      base.send(:include, InstanceMethods)
      
      base.class_eval do
        alias_method :send_notification_without_helpdesk, :send_notification
        alias_method :send_notification, :send_notification_with_helpdesk
      end
    end

    module InstanceMethods
      # Overrides the send_notification method which
      # is only called on journal updates
      def send_notification_with_helpdesk
        if notify? && (Setting.notified_events.include?('issue_updated') ||
            (Setting.notified_events.include?('issue_note_added') && notes.present?) ||
            (Setting.notified_events.include?('issue_status_updated') && new_status.present?) ||
            (Setting.notified_events.include?('issue_assigned_to_updated') && detail_for_attribute('assigned_to_id').present?) ||
            (Setting.notified_events.include?('issue_priority_updated') && new_value_for('priority_id').present?)
          )
          Mailer.deliver_issue_edit(self)
        end
        # do not send on private-notes
        if private_notes == true && send_to_owner == true 
          self.send_to_owner = false
          self.save( validate: false )
        end
        # sending email notifications to the supportclient
        # only if the send_to_owner checkbox was checked
        if send_to_owner == true && notes.length != 0
          issue = self.journalized.reload
          owner_email = issue.custom_value_for( CustomField.find_by_name('owner-email') ).value
          HelpdeskMailer.email_to_supportclient(
            issue, {
              recipient: owner_email,
              journal:   self,
              text:      notes
            }
          ).deliver unless owner_email.blank?
        end
      end
      
    end # module InstanceMethods
  end # module JournalPatch
end # module RedmineHelpdesk

# Add module to Journal class
Journal.send(:include, ::RedmineHelpdesk::JournalPatch)


================================================
FILE: lib/redmine_helpdesk/mail_handler_patch.rb
================================================
module RedmineHelpdesk
  module MailHandlerPatch
    def self.included(base) # :nodoc:
      base.send(:include, InstanceMethods)

      base.class_eval do
        alias_method :dispatch_to_default_without_helpdesk, :dispatch_to_default
        alias_method :dispatch_to_default, :dispatch_to_default_with_helpdesk
        # needed for reopening a closed issue
        alias_method :receive_issue_reply_without_helpdesk, :receive_issue_reply
        alias_method :receive_issue_reply, :receive_issue_reply_with_helpdesk
      end
    end

    module InstanceMethods
      private
      # Overrides the dispatch_to_default method to
      # set the owner-email of a new issue created by
      # an email request
      def dispatch_to_default_with_helpdesk
        issue = receive_issue
        issue.reload # prevent ActiveRecord::StaleObjectError
        roles = if issue.author.class == AnonymousUser
          Role.where(builtin: issue.author.id)
        else
          issue.author.roles_for_project(issue.project)
        end
        # add owner-email only if the author has assigned some role with
        # permission treat_user_as_supportclient enabled
        if issue.author.type.eql?("AnonymousUser") || roles.any? {|role| role.allowed_to?(:treat_user_as_supportclient) }
          sender_email = @email.from.first
          
          # any cc handling needed?
          custom_value = custom_field_value(issue.project,'cc-handling')
          if (!@email.cc.nil?) && (custom_value.value == '1')
            carbon_copy = @email[:cc].formatted.join(', ')
            custom_value = custom_field_value(issue,'copy-to')
            custom_value.value = carbon_copy
            custom_value.save( validate: false ) # skip validation!
          else
            carbon_copy = nil
          end
          
          issue.description = email_details + issue.description
          issue.save( validate: false ) # skip validation!
          
          custom_value = custom_field_value(issue,'owner-email')
          if custom_value.value.to_s.strip.empty?
            custom_value.value = sender_email
            custom_value.save( validate: false ) # skip validation!
          else
            # Email owner field was already set by some preprocess hooks.
            # So now we need to send message to another recepient.
            sender_email = custom_value.value.to_s.strip
          end
          
          # regular email sending to known users is done
          # on the first issue.save. So we need to send
          # the notification email to the supportclient
          # on our own.
          HelpdeskMailer.email_to_supportclient(
            issue, {
              recipient:   sender_email,
              carbon_copy: carbon_copy
            }
          ).deliver
        end
        after_dispatch_to_default_hook issue
        return issue
      end

      # let other plugins the chance to override this
      # method to hook into dispatch_to_default
      def after_dispatch_to_default_hook(issue)
      end

      # Fix an issue with email.has_attachments?
      def add_attachments(obj)
         if !email.attachments.nil? && email.attachments.size > 0
           email.attachments.each do |attachment|
             obj.attachments << Attachment.create(
               container:    obj,
               file:         attachment.decoded,
               filename:     attachment.filename,
               author:       user,
               content_type: attachment.mime_type
             )
          end
        end
      end

      # Overrides the receive_issue_reply method
      def receive_issue_reply_with_helpdesk(issue_id, from_journal=nil)
        issue = Issue.find_by_id(issue_id)
        return unless issue

        # reopening a closed issues by email
        custom_value = custom_field_value(issue.project,'reopen-issues-with')
        if issue.closed? && custom_value.present? && custom_value.value.present?
          status_id = IssueStatus.where("name = ?", custom_value.value).try(:first).try(:id)
          unless status_id.nil?
            issue.status_id = status_id
            issue.save
          end
        end

        # call original method
        receive_issue_reply_without_helpdesk(issue_id, from_journal)

        # store email-details before each note
        last_journal = Journal.find(issue.last_journal_id)
        last_journal.notes = email_details + last_journal.notes
        last_journal.save

        return last_journal
      end
      
      def custom_field_value(issue,name)
        custom_field = CustomField.find_by_name(name)
        CustomValue.where(
          "customized_id = ? AND custom_field_id = ?", issue.id, custom_field.id
        ).first
      end

      def email_details
        details =  "From: " + @email[:from].formatted.first + "\n"
        details << "To:   " + @email[:to].formatted.join(', ') + "\n" if !@email.to.nil?
        details << "Cc:   " + @email[:cc].formatted.join(', ') + "\n" if !@email.cc.nil?
        details << "Date: " + @email[:date].to_s + "\n"
        "<pre>\n" + Mail::Encodings.unquote_and_convert_to(details, 'utf-8') + "</pre>\n\n"
      end

    end # module InstanceMethods
  end # module MailHandlerPatch
end # module RedmineHelpdesk

# Add module to MailHandler class
MailHandler.send(:include, ::RedmineHelpdesk::MailHandlerPatch)


================================================
FILE: lib/redmine_helpdesk/mailer_patch.rb
================================================
module RedmineHelpdesk
  module MailerPatch
    def self.included(base) # :nodoc:
      base.send(:include, InstanceMethods)
      
      base.class_eval do
        alias_method :issue_edit_without_helpdesk, :issue_edit
        alias_method :issue_edit, :issue_edit_with_helpdesk
      end
    end

    module InstanceMethods
      # Overrides the issue_edit method which is only
      # be called on existing tickets. We will add the
      # owner-email to the recipients only if no email-
      # footer text is available.
      def issue_edit_with_helpdesk(user, journal)
        issue = journal.journalized
        redmine_headers 'Project' => issue.project.identifier,
                        'Issue-Id' => issue.id,
                        'Issue-Author' => issue.author.login,
                        'Issue-Tracker' => issue.tracker
        redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
        message_id journal
        references issue
        @author = journal.user

        # process reply-separator
        f = CustomField.find_by_name('helpdesk-reply-separator')
        reply_separator = issue.project.custom_value_for(f).try(:value)
        if !reply_separator.blank? and !journal.notes.nil?
          journal.notes = journal.notes.gsub(/#{reply_separator}.*/m, '')
          journal.save(:validate => false)
        end

        # add owner-email to the recipients
        alternative_user = nil
        begin
          if journal.send_to_owner == true
            f = CustomField.find_by_name('helpdesk-email-footer')
            p = issue.project
            owner_email = issue.custom_value_for( CustomField.find_by_name('owner-email') ).value
            if !owner_email.blank? && !f.nil? && !p.nil? && p.custom_value_for(f).try(:value).blank?
              alternative_user = owner_email
            end
          end
        rescue Exception => e
          Rails.logger.error "Error while adding owner-email to recipients of email notification: \"#{e.message}\"."
        end

        # any cc handling needed?
        cc_users = nil
        begin
          # any cc handling needed?
          if alternative_user.present?
            custom_field = CustomField.find_by_name('cc-handling')
            custom_value = CustomValue.where(
              "customized_id = ? AND custom_field_id = ?", issue.project.id, custom_field.id
            ).first
            cc_users = custom_value.value.split(',').map(&:strip) if custom_value.value.present?
          end
        rescue Exception => e
          Rails.logger.error "Error while adding cc-users to recipients of email notification: \"#{e.message}\"."
        end

        s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
        s += "(#{issue.status.name}) " if journal.new_value_for('status_id') && Setting.show_status_changes_in_mail_subject?
        s += issue.subject
        u = (alternative_user.present? ? alternative_user : user)
        @issue = issue
        @user = u
        @journal = journal
        @journal_details = journal.visible_details
        @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
        mail(
          :to => u,
          :cc => cc_users,
          :subject => s
        )
      end
      
    end # module InstanceMethods
  end # module MailerPatch
end # module RedmineHelpdesk

# Add module to Mailer class
Mailer.send(:include, ::RedmineHelpdesk::MailerPatch)


================================================
FILE: lib/tasks/local-db.rake
================================================
namespace :helpdesk do
  namespace :localdb do
    db_label = 'helpdesk-db'

    def get_env ()
      db_name = 'redmine'
      db_host = 'localhost'
      db_user = 'root'

      db_adapter = ENV['DATABASE_ADAPTER']
      case db_adapter
      when "mysql"
        env = "-e MYSQL_DATABASE=#{db_name} "\
              "-e MYSQL_ALLOW_EMPTY_PASSWORD=yes "
      when "postgresql"
        env = "-e POSTGRES_DB=#{db_name} "\
              "-e POSTGRES_USER=#{db_user} "\
      when "postgresql_ext"
        env = "-e POSTGRES_DB=#{db_name} "\
              "-e POSTGRES_USER=#{db_user}"
      else
        raise StandardError.new "Cannot start local db"
      end
      env
    end

    def get_port ()
      db_adapter = ENV['DATABASE_ADAPTER']
      case db_adapter
      when "mysql"
        port = 3306
      when "postgresql"
        port = 5432
      when "postgresql_ext"
        port = 5432
      else
        raise StandardError.new "Cannot start local db"
      end
      port
    end

    def get_image ()
      db_adapter = ENV['DATABASE_ADAPTER']
      case db_adapter
      when "mysql"
        image = "mysql"
      when "postgresql"
        image = "postgres"
      when "postgresql_ext"
        image = "postgres"
      else
        raise StandardError.new "Cannot start local db"
      end
      image
    end

    task :start => :stop do
      env = get_env()
      port = get_port()
      image = get_image()
      cmd = "docker run -d --name #{db_label} "\
              "--net=host "\
              "#{env} "\
              "#{image}"
      puts cmd
      system(cmd)
    end

    task :stop do
      system("docker stop #{db_label}")
      system("docker rm #{db_label}")
    end
  end
end


================================================
FILE: lib/tasks/plugin_ci.rake
================================================
namespace :helpdesk do
  plugin_root = File.expand_path('../../../', __FILE__)
  coverage_dir = "#{plugin_root}/coverage"

  desc 'Runs :ci target from plugin scope in test/app'
  task :ext_ci do
    cd('test/app') do
      sh('bundle exec rake helpdesk:ci')
    end
  end

  desc 'Prepared and configures DB in Docker container'
  task :prepare_local => ['helpdesk:localdb:start',
                          'helpdesk:redmine:configure_db'] do
    Rake::Task['helpdesk:install'].invoke()
  end

  desc 'Runs bundle install from plugin scop in test/app'
  task :install do
    cd('test/app') do
      sh('bundle install --without production development rmagick')
    end
  end

  desc 'Runs migrate from plugin scope in test/app'
  task :migrate do
    cd('test/app') do
      sh('bundle exec rake generate_secret_token')
      sh('bundle exec rake db:migrate')
    end
  end

  desc 'Prepares and runs the test suite.'
  task :ci => ['redmine:plugins:migrate',
               'helpdesk:test']

  desc 'Runs Redmine plugin tests with single CodeClimate TestReporter invocation.'
  task :test => [ 'helpdesk:test:clear_coverage_data',
                  'helpdesk:test:run' ]

  namespace :test do
    task :run do
      Rake::Task['redmine:plugins:test:units'].invoke
      Rake::Task['redmine:plugins:test:functionals'].invoke

      # require "simplecov"
      # require "codeclimate-test-reporter"
      # SimpleCov.coverage_dir "plugins/coverage"
      # CodeClimate::TestReporter.configure do |config|
      #   config.git_dir = "plugins/#{ENV['GITHUB_PROJECT']}"
      # end
      # CodeClimate::TestReporter::Formatter.new.format(SimpleCov.result)
    end

    task :clear_coverage_data do
      rm_rf coverage_dir
    end
  end
end


================================================
FILE: lib/tasks/redmine.rake
================================================
require 'fileutils'

namespace :helpdesk do
  namespace :redmine do
    plugin_root = File.expand_path('../../../', __FILE__)
    redmine_path = "#{plugin_root}/test/app"
    tmp_dir = "#{plugin_root}/tmp"

    redmine_source_url = "http://www.redmine.org/releases"
    redmine_version = ENV['REDMINE_VERSION'] || "3.2.0"
    redmine_name = "redmine-#{redmine_version}"
    redmine_package = "#{redmine_name}.tar.gz"
    redmine_url = "#{redmine_source_url}/#{redmine_package}"

    version = redmine_version.split(".")
    major = version[0]
    minor = version[1]
    patch = version[2]

    task :install => [ :remove,
                       :print_env,
                       :download_tarball,
                       :extract_tarball,
                       :configure_db,
                       :link_plugin,
                       :print_result ]

    task :print_env do
      if ENV['DATABASE_ADAPTER'].nil?
        raise StandardError.new "Database adapter not defined"
      end

      puts ""
      puts "######################"
      puts "REDMINE INSTALLATION SCRIPT"
      puts ""
      puts "REDMINE_VERSION  : #{redmine_version}"
      puts "REDMINE_URL      : #{redmine_url}"
      puts "DATABASE ADAPTER : #{ENV['DATABASE_ADAPTER']}"
      puts ""
    end

    task :remove do
      rm_rf redmine_path
    end

    task :download_tarball do
      mkdir_p tmp_dir
      Dir.chdir(tmp_dir) do
        puts "Downloading tarball"
        if !system("wget #{redmine_url}")
          raise StandardError.new "download failed"
        end
      end
    end

    task :extract_tarball do
      Dir.chdir(tmp_dir) do
        puts "Extracting tarball"
        if !system("tar xf #{redmine_package}")
          raise StandardError.new "download failed"
        end
        mv "#{redmine_name}", "#{redmine_path}", :force => true
        rm_rf tmp_dir
      end
    end

    task :configure_db do
      puts "Configuring database"
      db_adapter = ENV['DATABASE_ADAPTER']
      case db_adapter
      when "mysql"
        a = "mysql"
      when "postgresql"
        a = "postgres"
      when "postgresql_ext"
        a = "postgres_ext"
      when "sqlite"
        a = "sqlite"
      else
        raise StandardError.new "Error copying config files"
      end
      cp "#{plugin_root}/test/confs/database_#{a}.yml",
        "#{redmine_path}/config/database.yml", :verbose => true
    end

    task :print_result do
      puts "Dummy Redmine dir listing"
      Dir["#{redmine_path}/*"].each do |f|
        puts f.sub("#{redmine_path}", "")
      end
      puts ""
      puts "Dummy Redmine plugin dir listing"
      Dir["#{redmine_path}/plugins/*"].each do |f|
        puts f.sub("#{redmine_path}/plugins", "")
      end
      puts ""
    end

    task :link_plugin do
      plugin_dir = "#{redmine_path}/plugins/redmine_helpdesk"
      ln_sf plugin_root, plugin_dir
    end
  end
end


================================================
FILE: test/confs/database_mysql.yml
================================================
## MySQL configuration example
## Data come from environment variables so the test suite can be run
## on Travis or Jenkins (see https://github.com/codevise/jenkins-mysql-job-databases-plugin)
production:
  adapter: mysql2
  database: <%= ENV['MYSQL_DATABASE'] || 'redmine' %>
  host: <%= ENV['MYSQL_HOST'] || '127.0.0.1' %>
  port: <%= ENV['MYSQL_PORT'] || '3306' %>
  username: <%= ENV['MYSQL_USER'] || 'root' %>
  password: <%= ENV['MYSQL_PASSWORD'] %>
  encoding: utf8

development:
  adapter: mysql2
  database: <%= ENV['MYSQL_DATABASE'] || 'redmine' %>
  host: <%= ENV['MYSQL_HOST'] || '127.0.0.1' %>
  port: <%= ENV['MYSQL_PORT'] || '3306' %>
  username: <%= ENV['MYSQL_USER'] || 'root' %>
  password: <%= ENV['MYSQL_PASSWORD'] %>
  encoding: utf8

test:
  adapter: mysql2
  database: <%= ENV['MYSQL_DATABASE'] || 'redmine' %>
  host: <%= ENV['MYSQL_HOST'] || '127.0.0.1' %>
  port: <%= ENV['MYSQL_PORT'] || '3306' %>
  username: <%= ENV['MYSQL_USER'] || 'root' %>
  password: <%= ENV['MYSQL_PASSWORD'] %>
  encoding: utf8


================================================
FILE: test/confs/database_postgres.yml
================================================
## PostgreSQL configuration example
## Data come from environment variables so the test suite can be run
## on Travis or Jenkins (see https://github.com/lmlima/jenkins-postgresql-job-databases-plugin)
production:
  adapter: postgresql
  database: <%= ENV['POSTGRES_DATABASE'] || 'redmine' %>
  username: <%= ENV['POSTGRES_USER'] || 'root' %>
  encoding: utf8

development:
  adapter: postgresql
  database: <%= ENV['POSTGRES_DATABASE'] || 'redmine' %>
  username: <%= ENV['POSTGRES_USER'] || 'root' %>
  encoding: utf8

test:
  adapter: postgresql
  database: <%= ENV['POSTGRES_DATABASE'] || 'redmine' %>
  username: <%= ENV['POSTGRES_USER'] || 'root' %>
  encoding: utf8


================================================
FILE: test/confs/database_postgres_ext.yml
================================================
## PostgreSQL configuration example
## Data come from environment variables so the test suite can be run
## on Travis or Jenkins (see https://github.com/lmlima/jenkins-postgresql-job-databases-plugin)
production:
  adapter: postgresql
  database: <%= ENV['POSTGRES_DATABASE'] || 'redmine' %>
  host: <%= ENV['POSTGRES_HOST'] || 'localhost' %>
  username: <%= ENV['POSTGRES_USER'] || 'root' %>
  encoding: utf8

development:
  adapter: postgresql
  database: <%= ENV['POSTGRES_DATABASE'] || 'redmine' %>
  host: <%= ENV['POSTGRES_HOST'] || 'localhost' %>
  username: <%= ENV['POSTGRES_USER'] || 'root' %>
  encoding: utf8

test:
  adapter: postgresql
  database: <%= ENV['POSTGRES_DATABASE'] || 'redmine' %>
  host: <%= ENV['POSTGRES_HOST'] || 'localhost' %>
  username: <%= ENV['POSTGRES_USER'] || 'root' %>
  encoding: utf8


================================================
FILE: test/confs/database_sqlite.yml
================================================
## SQLite3 configuration example
production:
  adapter: sqlite3
  database: db/redmine.sqlite3
development:
  adapter: sqlite3
  database: db/redmine.dev.sqlite3
test:
  adapter: sqlite3
  database: db/redmine.test.sqlite3


================================================
FILE: test/fixtures/2.6/attachments.yml
================================================
---
attachments_001:
  created_on: 2006-07-19 21:07:27 +02:00
  container_type: Issue
  container_id: 1
  downloads: 0
  disk_filename: 060719210727_source.rb
  disk_directory: "2006/07"
  digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
  id: 1
  filesize: 153
  filename: source.rb
  author_id: 1
  description: This is a Ruby source file
  content_type: application/x-ruby


================================================
FILE: test/fixtures/2.6/custom_fields.yml
================================================
---
custom_fields_001:
  name: owner-email
  regexp: ""
  type: IssueCustomField
  possible_values: ""
  id: 1
  is_required: false
  field_format: string
  default_value: ""
  editable: true
  visible: true
  position: 1
custom_fields_002:
  name: helpdesk-first-reply
  min_length: 1
  regexp: ""
  visible: false
  type: ProjectCustomField
  max_length: 100
  possible_values: ""
  id: 2
  is_required: false
  field_format: text
  default_value: ""
  editable: true
  position: 1
custom_fields_003:
  name: helpdesk-email-footer
  min_length: 1
  regexp: ""
  visible: false
  type: ProjectCustomField
  max_length: 100
  possible_values: ""
  id: 3
  is_required: false
  field_format: text
  default_value: ""
  editable: true
  position: 1
custom_fields_004:
  name: helpdesk-sender-email
  regexp: ""
  type: ProjectCustomField
  possible_values: ""
  id: 4
  is_required: false
  field_format: string
  default_value: false
  editable: true
  visible: true
  position: 1
custom_fields_005:
  name: helpdesk-send-to-owner-default
  regexp: ""
  type: ProjectCustomField
  possible_values: ""
  id: 5
  is_required: false
  field_format: bool
  default_value: false
  editable: true
  visible: false
  position: 1
custom_fields_006:
  name: helpdesk-subject
  min_length: 1
  regexp: ""
  visible: false
  type: ProjectCustomField
  max_length: 100
  possible_values: ""
  id: 6
  is_required: false
  field_format: text
  default_value: ""
  editable: true
  position: 1
custom_fields_007:
  name: helpdesk-send-first-reply
  visible: false
  type: ProjectCustomField
  id: 7
  is_required: false
  field_format: boolean
  default_value: true
  editable: true
  position: 1
custom_fields_008:
  name: title
  regexp: ""
  is_for_all: false
  type: UserCustomField
  possible_values: ""
  id: 8
  is_required: false
  field_format: string
  default_value: ""
  editable: true
  position: 1
custom_fields_009:
  name: motto
  regexp: ""
  is_for_all: false
  type: UserCustomField
  possible_values: ""
  id: 9
  is_required: false
  field_format: string
  default_value: ""
  editable: true
  position: 2
custom_fields_010:
  name: copy-to
  regexp: ""
  type: IssueCustomField
  possible_values: ""
  id: 10
  is_required: false
  field_format: string
  default_value: ""
  editable: true
  visible: true
  position: 1
custom_fields_011:
  name: cc-handling
  visible: false
  type: ProjectCustomField
  id: 11
  is_required: false
  field_format: bool
  default_value: false
  editable: true
  position: 1


================================================
FILE: test/fixtures/2.6/custom_fields_projects.yml
================================================
---
custom_fields_projects_001:
  custom_field_id: 1
  project_id: 1
custom_fields_projects_002:
  custom_field_id: 1
  project_id: 2
custom_fields_projects_003:
  custom_field_id: 10
  project_id: 1
custom_fields_projects_004:
  custom_field_id: 10
  project_id: 2
custom_fields_projects_005:
  custom_field_id: 1
  project_id: 4
custom_fields_projects_006:
  custom_field_id: 10
  project_id: 4


================================================
FILE: test/fixtures/2.6/custom_fields_trackers.yml
================================================
---
custom_fields_trackers_001:
  custom_field_id: 1
  tracker_id: 1
custom_fields_trackers_002:
  custom_field_id: 1
  tracker_id: 2
custom_fields_trackers_003:
  custom_field_id: 1
  tracker_id: 3
custom_fields_trackers_004:
  custom_field_id: 1
  tracker_id: 4
custom_fields_trackers_005:
  custom_field_id: 10
  tracker_id: 1
custom_fields_trackers_006:
  custom_field_id: 10
  tracker_id: 2
custom_fields_trackers_007:
  custom_field_id: 10
  tracker_id: 3
custom_fields_trackers_008:
  custom_field_id: 10
  tracker_id: 4


================================================
FILE: test/fixtures/2.6/custom_values.yml
================================================
---
custom_values_001:
  customized_type: Project
  custom_field_id: 2
  customized_id: 1
  id: 1
  value: "first reply"
custom_values_002:
  customized_type: Project
  custom_field_id: 3
  customized_id: 1
  id: 2
  value: "email footer"
custom_values_003:
  customized_type: Project
  custom_field_id: 4
  customized_id: 1
  id: 3
  value: reply@example.com
custom_values_004:
  customized_type: Project
  custom_field_id: 5
  customized_id: 1
  id: 4
  value: 0
custom_values_005:
  customized_type: Project
  custom_field_id: 11
  customized_id: 1
  id: 5
  value: 1
custom_values_006:
  customized_type: Project
  custom_field_id: 2
  customized_id: 2
  id: 6
  value: first reply
custom_values_007:
  customized_type: Project
  custom_field_id: 3
  customized_id: 2
  id: 7
  value: email footer
custom_values_008:
  customized_type: Project
  custom_field_id: 4
  customized_id: 2
  id: 8
  value: reply@example.com
custom_values_009:
  customized_type: Project
  custom_field_id: 5
  customized_id: 2
  id: 9
  value: 0
custom_values_010:
  customized_type: Project
  custom_field_id: 11
  customized_id: 2
  id: 10
  value: 1
custom_values_011:
  customized_type: Issue
  custom_field_id: 1
  customized_id: 1
  id: 11
  value: owner@example.com
custom_values_012:
  customized_type: Project
  custom_field_id: 2
  customized_id: 4
  id: 12
  value: first reply
custom_values_013:
  customized_type: Project
  custom_field_id: 3
  customized_id: 4
  id: 13
  value: email footer
custom_values_014:
  customized_type: Project
  custom_field_id: 4
  customized_id: 4
  id: 14
  value: reply@example.com
custom_values_015:
  customized_type: Project
  custom_field_id: 5
  customized_id: 4
  id: 15
  value: 0
custom_values_016:
  customized_type: Project
  custom_field_id: 11
  customized_id: 4
  id: 16
  value: 0


================================================
FILE: test/fixtures/2.6/enabled_modules.yml
================================================
---
enabled_modules_001:
  name: issue_tracking
  project_id: 1
  id: 1
enabled_modules_002:
  name: time_tracking
  project_id: 1
  id: 2
enabled_modules_003:
  name: files
  project_id: 1
  id: 3
enabled_modules_004:
  name: issue_tracking
  project_id: 2
  id: 4
enabled_modules_005:
  name: time_tracking
  project_id: 2
  id: 5
enabled_modules_006:
  name: files
  project_id: 2
  id: 6
enabled_modules_007:
  name: issue_tracking
  project_id: 4
  id: 7
enabled_modules_008:
  name: time_tracking
  project_id: 4
  id: 8
enabled_modules_009:
  name: files
  project_id: 4
  id: 9


================================================
FILE: test/fixtures/2.6/enumerations.yml
================================================
---
enumerations_001:
  name: Low
  id: 1
  type: IssuePriority
  active: true
  position: 1
  position_name: lowest
enumerations_002:
  name: Normal
  id: 2
  type: IssuePriority
  is_default: true
  active: true
  position: 2
  position_name: default
enumerations_003:
  name: High
  id: 3
  type: IssuePriority
  active: true
  position: 3
  position_name: high3
enumerations_004:
  name: Urgent
  id: 4
  type: IssuePriority
  active: true
  position: 4
  position_name: high2
enumerations_005:
  name: Immediate
  id: 5
  type: IssuePriority
  active: true
  position: 5
  position_name: highest


================================================
FILE: test/fixtures/2.6/issue_statuses.yml
================================================
--- 
issue_statuses_001: 
  id: 1
  name: New
  is_default: true
  is_closed: false
  position: 1
issue_statuses_002: 
  id: 2
  name: Assigned
  is_default: false
  is_closed: false
  position: 2
issue_statuses_003: 
  id: 3
  name: Resolved
  is_default: false
  is_closed: false
  position: 3
issue_statuses_004: 
  name: Feedback
  id: 4
  is_default: false
  is_closed: false
  position: 4
issue_statuses_005: 
  id: 5
  name: Closed
  is_default: false
  is_closed: true
  position: 5
issue_statuses_006: 
  id: 6
  name: Rejected
  is_default: false
  is_closed: true
  position: 6


================================================
FILE: test/fixtures/2.6/issues.yml
================================================
---
issues_001:
  created_on: 2015-03-05 21:41:21 +02:00
  project_id: 1
  updated_on: 2015-03-05 22:05:50 +02:00
  priority_id: 2
  subject: Can't print recipes
  id: 1
  fixed_version_id:
  category_id: 1
  description: Unable to print recipes
  tracker_id: 1
  assigned_to_id: 1
  author_id: 1
  status_id: 1
  start_date:
  due_date:
  root_id: 1
  lft: 1
  rgt: 2
  lock_version: 3
issues_002:
  created_on: 2006-07-19 21:04:21 +02:00
  project_id: 2
  updated_on: 2006-07-19 21:09:50 +02:00
  priority_id: 2
  subject: Add ingredients categories
  id: 2
  fixed_version_id:
  category_id:
  description: Ingredients of the recipe should be classified by categories
  tracker_id: 2
  assigned_to_id:
  author_id: 1
  status_id: 2
  start_date:
  due_date:
  root_id: 2
  lft: 1
  rgt: 2
  lock_version: 3


================================================
FILE: test/fixtures/2.6/journal_details.yml
================================================
---
journal_details_001:
  old_value:
  property: attachment
  id: 1
  value: 060719210727_source.rb
  prop_key: 1
  journal_id: 3


================================================
FILE: test/fixtures/2.6/journals.yml
================================================
---
journals_001:
  created_on: <%= 2.days.ago.to_date.to_s(:db) %>
  notes: "Journal notes"
  id: 1
  journalized_type: Issue
  user_id: 1
  journalized_id: 1
journals_002:
  created_on: <%= 1.days.ago.to_date.to_s(:db) %>
  notes: "Some notes."
  id: 2
  journalized_type: Issue
  user_id: 1
  journalized_id: 1
journals_003:
  created_on: <%= 1.days.ago.to_date.to_s(:db) %>
  notes: "Some notes with an attachment."
  id: 3
  journalized_type: Issue
  user_id: 1
  journalized_id: 1
journals_004:
  id: 4
  created_on: <%= 1.days.ago.to_date.to_s(:db) %>
  notes: "A comment on an issue."
  user_id: 1
  journalized_type: Issue
  journalized_id: 2


================================================
FILE: test/fixtures/2.6/member_roles.yml
================================================
---
member_roles_001:
  id: 1
  role_id: 1
  member_id: 1
member_roles_002:
  id: 2
  role_id: 1
  member_id: 2
member_roles_003:
  id: 3
  role_id: 1
  member_id: 3
member_roles_004:
  id: 4
  role_id: 6
  member_id: 4


================================================
FILE: test/fixtures/2.6/members.yml
================================================
---
members_001:
  created_on: 2006-07-19 19:35:33 +02:00
  project_id: 1
  id: 1
  user_id: 1
  mail_notification: true
members_002:
  created_on: 2006-07-19 19:35:36 +02:00
  project_id: 2
  id: 2
  user_id: 1
  mail_notification: true
members_003:
  created_on: 2006-07-19 19:35:36 +02:00
  project_id: 3
  id: 3
  user_id: 1
  mail_notification: true
members_004:
  created_on: 2006-07-19 19:35:36 +02:00
  project_id: 2
  id: 4
  user_id: 2
  mail_notification: false
members_005:
  created_on: 2006-07-19 19:35:36 +02:00
  project_id: 4
  id: 5
  user_id: 1
  mail_notification: true


================================================
FILE: test/fixtures/2.6/projects.yml
================================================
---
projects_001:
  created_on: 2015-03-05 19:13:59 +02:00
  name: Helpdesk Project 1
  updated_on: 2015-03-05 22:53:01 +02:00
  id: 1
  description: First helpdesk project
  homepage: ""
  is_public: true
  identifier: helpdesk_project_1
  parent_id:
  lft: 1
  rgt: 2
projects_002:
  created_on: 2015-03-05 19:14:19 +02:00
  name: Helpdesk Project 2
  updated_on: 2015-03-05 19:14:19 +02:00
  id: 2
  description: Second helpdesk project
  homepage: ""
  is_public: false
  identifier: helpdesk_project_2
  parent_id:
  lft: 3
  rgt: 4
projects_003:
  created_on: 2015-03-05 19:15:21 +02:00
  name: Irrelevant Project
  updated_on: 2015-03-05 19:18:12 +02:00
  id: 3
  description: Project that has no helpdesk features
  homepage: ""
  is_public: true
  identifier: irrelevant_project
  parent_id:
  lft: 5
  rgt: 6
projects_004:
  created_on: 2015-03-05 19:14:19 +02:00
  name: Helpdesk Project 4
  updated_on: 2015-03-05 19:14:19 +02:00
  id: 4
  description: Disabled copy-to helpdesk project
  homepage: ""
  is_public: true
  identifier: helpdesk_project_4
  parent_id:
  lft: 6
  rgt: 7



================================================
FILE: test/fixtures/2.6/projects_trackers.yml
================================================
---
projects_trackers_001:
  project_id: 1
  tracker_id: 1
projects_trackers_002:
  project_id: 1
  tracker_id: 2
projects_trackers_003:
  project_id: 1
  tracker_id: 3
projects_trackers_004:
  project_id: 2
  tracker_id: 1
projects_trackers_005:
  project_id: 2
  tracker_id: 2
projects_trackers_006:
  project_id: 2
  tracker_id: 3
projects_trackers_007:
  project_id: 3
  tracker_id: 1
projects_trackers_008:
  project_id: 3
  tracker_id: 2
projects_trackers_009:
  project_id: 3
  tracker_id: 3
projects_trackers_010:
  project_id: 4
  tracker_id: 1
projects_trackers_011:
  project_id: 4
  tracker_id: 2
projects_trackers_012:
  project_id: 4
  tracker_id: 3


================================================
FILE: test/fixtures/2.6/roles.yml
================================================
---
roles_001:
  name: Manager
  id: 1
  builtin: 0
  issues_visibility: all
  permissions: |
    ---
    - :add_project
    - :edit_project
    - :close_project
    - :select_project_modules
    - :manage_members
    - :manage_versions
    - :manage_categories
    - :view_issues
    - :add_issues
    - :edit_issues
    - :manage_issue_relations
    - :manage_subtasks
    - :add_issue_notes
    - :move_issues
    - :delete_issues
    - :view_issue_watchers
    - :add_issue_watchers
    - :set_issues_private
    - :set_notes_private
    - :view_private_notes
    - :delete_issue_watchers
    - :manage_public_queries
    - :save_queries
    - :view_gantt
    - :view_calendar
    - :log_time
    - :view_time_entries
    - :edit_time_entries
    - :delete_time_entries
    - :manage_news
    - :comment_news
    - :view_documents
    - :add_documents
    - :edit_documents
    - :delete_documents
    - :view_wiki_pages
    - :export_wiki_pages
    - :view_wiki_edits
    - :edit_wiki_pages
    - :delete_wiki_pages_attachments
    - :protect_wiki_pages
    - :delete_wiki_pages
    - :rename_wiki_pages
    - :add_messages
    - :edit_messages
    - :delete_messages
    - :manage_boards
    - :view_files
    - :manage_files
    - :browse_repository
    - :manage_repository
    - :view_changesets
    - :manage_related_issues
    - :manage_project_activities

  position: 1
roles_002:
  name: Developer
  id: 2
  builtin: 0
  issues_visibility: default
  permissions: |
    ---
    - :edit_project
    - :manage_members
    - :manage_versions
    - :manage_categories
    - :view_issues
    - :add_issues
    - :edit_issues
    - :manage_issue_relations
    - :manage_subtasks
    - :add_issue_notes
    - :move_issues
    - :delete_issues
    - :view_issue_watchers
    - :save_queries
    - :view_gantt
    - :view_calendar
    - :log_time
    - :view_time_entries
    - :edit_own_time_entries
    - :manage_news
    - :comment_news
    - :view_documents
    - :add_documents
    - :edit_documents
    - :delete_documents
    - :view_wiki_pages
    - :view_wiki_edits
    - :edit_wiki_pages
    - :protect_wiki_pages
    - :delete_wiki_pages
    - :add_messages
    - :edit_own_messages
    - :delete_own_messages
    - :manage_boards
    - :view_files
    - :manage_files
    - :browse_repository
    - :view_changesets

  position: 2
roles_003:
  name: Reporter
  id: 3
  builtin: 0
  issues_visibility: default
  permissions: |
    ---
    - :edit_project
    - :manage_members
    - :manage_versions
    - :manage_categories
    - :view_issues
    - :add_issues
    - :edit_issues
    - :manage_issue_relations
    - :add_issue_notes
    - :move_issues
    - :view_issue_watchers
    - :save_queries
    - :view_gantt
    - :view_calendar
    - :log_time
    - :view_time_entries
    - :manage_news
    - :comment_news
    - :view_documents
    - :add_documents
    - :edit_documents
    - :delete_documents
    - :view_wiki_pages
    - :view_wiki_edits
    - :edit_wiki_pages
    - :delete_wiki_pages
    - :add_messages
    - :manage_boards
    - :view_files
    - :manage_files
    - :browse_repository
    - :view_changesets

  position: 3
roles_004:
  name: Non member
  id: 4
  builtin: 1
  issues_visibility: default
  permissions: |
    ---
    - :view_issues
    - :add_issues
    - :edit_issues
    - :manage_issue_relations
    - :add_issue_notes
    - :save_queries
    - :view_gantt
    - :view_calendar
    - :log_time
    - :view_time_entries
    - :comment_news
    - :view_documents
    - :view_wiki_pages
    - :view_wiki_edits
    - :edit_wiki_pages
    - :add_messages
    - :view_files
    - :manage_files
    - :browse_repository
    - :view_changesets

  position: 4
roles_005:
  name: Anonymous
  id: 5
  builtin: 2
  issues_visibility: default
  permissions: |
    ---
    - :treat_user_as_supportclient
    - :view_issues
    - :add_issue_notes
    - :view_gantt
    - :view_calendar
    - :view_time_entries
    - :view_documents
    - :view_wiki_pages
    - :view_wiki_edits
    - :view_files
    - :browse_repository
    - :view_changesets

  position: 5
roles_006:
  name: SupportClient
  id: 6
  builtin: 0
  issues_visibility: default
  permissions: |
    ---
    - :treat_user_as_supportclient
    - :add_issues
    - :add_issue_notes
  position: 6


================================================
FILE: test/fixtures/2.6/trackers.yml
================================================
--- 
trackers_001: 
  name: Bug
  id: 1
  is_in_chlog: true
  position: 1
trackers_002: 
  name: Feature request
  id: 2
  is_in_chlog: true
  position: 2
trackers_003: 
  name: Support request
  id: 3
  is_in_chlog: false
  position: 3


================================================
FILE: test/fixtures/2.6/users.yml
================================================
---
users_001:
  created_on: 2015-03-05 19:34:07 +02:00
  status: 1
  last_login_on:
  language: en
  # password = foo
  salt: 3126f764c3c5ac61cbfc103f25f934cf
  hashed_password: 9e4dd7eeb172c12a0691a6d9d3a269f7e9fe671b
  updated_on: 2015-03-05 19:34:07 +02:00
  admin: true
  mail: rhill@somenet.foo
  lastname: Hill
  firstname: Robert
  id: 1
  auth_source_id:
  mail_notification: all
  login: normaluser
  type: User
users_002:
  created_on: 2015-03-05 19:33:19 +02:00
  status: 1
  last_login_on:
  language: en
  # password = foo
  salt: 7599f9963ec07b5a3b55b354407120c0
  hashed_password: 8f659c8d7c072f189374edacfa90d6abbc26d8ed
  updated_on: 2015-03-05 19:33:19 +02:00
  admin: false
  mail: dlopper@somenet.foo
  lastname: Lopper
  firstname: Dave
  id: 2
  auth_source_id:
  mail_notification: all
  login: supportclient
  type: User
users_003:
  id: 3
  created_on: 2006-07-19 19:33:19 +02:00
  status: 0
  last_login_on:
  language: ''
  hashed_password: 1
  updated_on: 2006-07-19 19:33:19 +02:00
  admin: false
  lastname: Anonymous
  firstname: ''
  auth_source_id:
  mail_notification: only_my_events
  login: ''
  type: AnonymousUser


================================================
FILE: test/fixtures/3.0/attachments.yml
================================================
---
attachments_001:
  created_on: 2006-07-19 21:07:27 +02:00
  container_type: Issue
  container_id: 1
  downloads: 0
  disk_filename: 060719210727_source.rb
  disk_directory: "2006/07"
  digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
  id: 1
  filesize: 153
  filename: source.rb
  author_id: 1
  description: This is a Ruby source file
  content_type: application/x-ruby


================================================
FILE: test/fixtures/3.0/custom_fields.yml
================================================
---
custom_fields_001:
  name: owner-email
  regexp: ""
  type: IssueCustomField
  possible_values: ""
  id: 1
  is_required: false
  field_format: string
  default_value: ""
  editable: true
  visible: true
  position: 1
custom_fields_002:
  name: helpdesk-first-reply
  min_length: 1
  regexp: ""
  visible: false
  type: ProjectCustomField
  max_length: 100
  possible_values: ""
  id: 2
  is_required: false
  field_format: text
  default_value: ""
  editable: true
  position: 1
custom_fields_003:
  name: helpdesk-email-footer
  min_length: 1
  regexp: ""
  visible: false
  type: ProjectCustomField
  max_length: 100
  possible_values: ""
  id: 3
  is_required: false
  field_format: text
  default_value: ""
  editable: true
  position: 1
custom_fields_004:
  name: helpdesk-sender-email
  regexp: ""
  type: ProjectCustomField
  possible_values: ""
  id: 4
  is_required: false
  field_format: string
  default_value: false
  editable: true
  visible: true
  position: 1
custom_fields_005:
  name: helpdesk-send-to-owner-default
  regexp: ""
  type: ProjectCustomField
  possible_values: ""
  id: 5
  is_required: false
  field_format: bool
  default_value: false
  editable: true
  visible: false
  position: 1
custom_fields_006:
  name: helpdesk-subject
  min_length: 1
  regexp: ""
  visible: false
  type: ProjectCustomField
  max_length: 100
  possible_values: ""
  id: 6
  is_required: false
  field_format: text
  default_value: ""
  editable: true
  position: 1
custom_fields_007:
  name: helpdesk-send-first-reply
  visible: false
  type: ProjectCustomField
  id: 7
  is_required: false
  field_format: boolean
  default_value: true
  editable: true
  position: 1
custom_fields_008:
  name: title
  regexp: ""
  is_for_all: false
  type: UserCustomField
  possible_values: ""
  id: 8
  is_required: false
  field_format: string
  default_value: ""
  editable: true
  position: 1
custom_fields_009:
  name: motto
  regexp: ""
  is_for_all: false
  type: UserCustomField
  possible_values: ""
  id: 9
  is_required: false
  field_format: string
  default_value: ""
  editable: true
  position: 2
custom_fields_010:
  name: copy-to
  regexp: ""
  type: IssueCustomField
  possible_values: ""
  id: 10
  is_required: false
  field_format: string
  default_value: ""
  editable: true
  visible: true
  position: 1
custom_fields_011:
  name: cc-handling
  visible: false
  type: ProjectCustomField
  id: 11
  is_required: false
  field_format: bool
  default_value: false
  editable: true
  position: 1


================================================
FILE: test/fixtures/3.0/custom_fields_projects.yml
================================================
---
custom_fields_projects_001:
  custom_field_id: 1
  project_id: 1
custom_fields_projects_002:
  custom_field_id: 1
  project_id: 2
custom_fields_projects_003:
  custom_field_id: 10
  project_id: 1
custom_fields_projects_004:
  custom_field_id: 10
  project_id: 2
custom_fields_projects_005:
  custom_field_id: 1
  project_id: 4
custom_fields_projects_006:
  custom_field_id: 10
  project_id: 4


================================================
FILE: test/fixtures/3.0/custom_fields_trackers.yml
================================================
---
custom_fields_trackers_001:
  custom_field_id: 1
  tracker_id: 1
custom_fields_trackers_002:
  custom_field_id: 1
  tracker_id: 2
custom_fields_trackers_003:
  custom_field_id: 1
  tracker_id: 3
custom_fields_trackers_004:
  custom_field_id: 1
  tracker_id: 4
custom_fields_trackers_005:
  custom_field_id: 10
  tracker_id: 1
custom_fields_trackers_006:
  custom_field_id: 10
  tracker_id: 2
custom_fields_trackers_007:
  custom_field_id: 10
  tracker_id: 3
custom_fields_trackers_008:
  custom_field_id: 10
  tracker_id: 4


================================================
FILE: test/fixtures/3.0/custom_values.yml
================================================
---
custom_values_001:
  customized_type: Project
  custom_field_id: 2
  customized_id: 1
  id: 1
  value: "first reply"
custom_values_002:
  customized_type: Project
  custom_field_id: 3
  customized_id: 1
  id: 2
  value: "email footer"
custom_values_003:
  customized_type: Project
  custom_field_id: 4
  customized_id: 1
  id: 3
  value: reply@example.com
custom_values_004:
  customized_type: Project
  custom_field_id: 5
  customized_id: 1
  id: 4
  value: 0
custom_values_005:
  customized_type: Project
  custom_field_id: 11
  customized_id: 1
  id: 5
  value: 1
custom_values_006:
  customized_type: Project
  custom_field_id: 2
  customized_id: 2
  id: 6
  value: first reply
custom_values_007:
  customized_type: Project
  custom_field_id: 3
  customized_id: 2
  id: 7
  value: email footer
custom_values_008:
  customized_type: Project
  custom_field_id: 4
  customized_id: 2
  id: 8
  value: reply@example.com
custom_values_009:
  customized_type: Project
  custom_field_id: 5
  customized_id: 2
  id: 9
  value: 0
custom_values_010:
  customized_type: Project
  custom_field_id: 11
  customized_id: 2
  id: 10
  value: 1
custom_values_011:
  customized_type: Issue
  custom_field_id: 1
  customized_id: 1
  id: 11
  value: owner@example.com
custom_values_012:
  customized_type: Project
  custom_field_id: 2
  customized_id: 4
  id: 12
  value: first reply
custom_values_013:
  customized_type: Project
  custom_field_id: 3
  customized_id: 4
  id: 13
  value: email footer
custom_values_014:
  customized_type: Project
  custom_field_id: 4
  customized_id: 4
  id: 14
  value: reply@example.com
custom_values_015:
  customized_type: Project
  custom_field_id: 5
  customized_id: 4
  id: 15
  value: 0
custom_values_016:
  customized_type: Project
  custom_field_id: 11
  customized_id: 4
  id: 16
  value: 0


================================================
FILE: test/fixtures/3.0/email_addresses.yml
================================================
---
email_address_001:
  id: 1
  user_id: 1
  address: rhill@somenet.foo
  is_default: true
  created_on: 2006-07-19 19:34:07 +02:00
  updated_on: 2006-07-19 19:34:07 +02:00
email_address_002:
  id: 2
  user_id: 2
  address: dlopper@somenet.foo
  is_default: true
  created_on: 2006-07-19 19:34:07 +02:00
  updated_on: 2006-07-19 19:34:07 +02:00


================================================
FILE: test/fixtures/3.0/enabled_modules.yml
================================================
---
enabled_modules_001:
  name: issue_tracking
  project_id: 1
  id: 1
enabled_modules_002:
  name: time_tracking
  project_id: 1
  id: 2
enabled_modules_003:
  name: files
  project_id: 1
  id: 3
enabled_modules_004:
  name: issue_tracking
  project_id: 2
  id: 4
enabled_modules_005:
  name: time_tracking
  project_id: 2
  id: 5
enabled_modules_006:
  name: files
  project_id: 2
  id: 6
enabled_modules_007:
  name: issue_tracking
  project_id: 4
  id: 7
enabled_modules_008:
  name: time_tracking
  project_id: 4
  id: 8
enabled_modules_009:
  name: files
  project_id: 4
  id: 9


================================================
FILE: test/fixtures/3.0/enumerations.yml
================================================
---
enumerations_001:
  name: Low
  id: 1
  type: IssuePriority
  active: true
  position: 1
  position_name: lowest
enumerations_002:
  name: Normal
  id: 2
  type: IssuePriority
  is_default: true
  active: true
  position: 2
  position_name: default
enumerations_003:
  name: High
  id: 3
  type: IssuePriority
  active: true
  position: 3
  position_name: high3
enumerations_004:
  name: Urgent
  id: 4
  type: IssuePriority
  active: true
  position: 4
  position_name: high2
enumerations_005:
  name: Immediate
  id: 5
  type: IssuePriority
  active: true
  position: 5
  position_name: highest


================================================
FILE: test/fixtures/3.0/issue_statuses.yml
================================================
---
issue_statuses_001:
  id: 1
  name: New
  is_closed: false
  position: 1
issue_statuses_002:
  id: 2
  name: Assigned
  is_closed: false
  position: 2
issue_statuses_003:
  id: 3
  name: Resolved
  is_closed: false
  position: 3
issue_statuses_004:
  name: Feedback
  id: 4
  is_closed: false
  position: 4
issue_statuses_005:
  id: 5
  name: Closed
  is_closed: true
  position: 5
issue_statuses_006:
  id: 6
  name: Rejected
  is_closed: true
  position: 6


================================================
FILE: test/fixtures/3.0/issues.yml
================================================
---
issues_001:
  created_on: 2015-03-05 21:41:21 +02:00
  project_id: 1
  updated_on: 2015-03-05 22:05:50 +02:00
  priority_id: 2
  subject: Can't print recipes
  id: 1
  fixed_version_id:
  category_id: 1
  description: Unable to print recipes
  tracker_id: 1
  assigned_to_id: 1
  author_id: 1
  status_id: 1
  start_date:
  due_date:
  root_id: 1
  lft: 1
  rgt: 2
  lock_version: 3
issues_002:
  created_on: 2006-07-19 21:04:21 +02:00
  project_id: 2
  updated_on: 2006-07-19 21:09:50 +02:00
  priority_id: 2
  subject: Add ingredients categories
  id: 2
  fixed_version_id:
  category_id:
  description: Ingredients of the recipe should be classified by categories
  tracker_id: 2
  assigned_to_id:
  author_id: 1
  status_id: 2
  start_date:
  due_date:
  root_id: 2
  lft: 1
  rgt: 2
  lock_version: 3


================================================
FILE: test/fixtures/3.0/journal_details.yml
================================================
---
journal_details_001:
  old_value:
  property: attachment
  id: 1
  value: 060719210727_source.rb
  prop_key: 1
  journal_id: 3


================================================
FILE: test/fixtures/3.0/journals.yml
================================================
---
journals_001:
  created_on: <%= 2.days.ago.to_date.to_s(:db) %>
  notes: "Journal notes"
  id: 1
  journalized_type: Issue
  user_id: 1
  journalized_id: 1
journals_002:
  created_on: <%= 1.days.ago.to_date.to_s(:db) %>
  notes: "Some notes."
  id: 2
  journalized_type: Issue
  user_id: 1
  journalized_id: 1
journals_003:
  created_on: <%= 1.days.ago.to_date.to_s(:db) %>
  notes: "Some notes with an attachment."
  id: 3
  journalized_type: Issue
  user_id: 1
  journalized_id: 1
journals_004:
  id: 4
  created_on: <%= 1.days.ago.to_date.to_s(:db) %>
  notes: "A comment on an issue."
  user_id: 1
  journalized_type: Issue
  journalized_id: 2


================================================
FILE: test/fixtures/3.0/member_roles.yml
================================================
---
member_roles_001:
  id: 1
  role_id: 1
  member_id: 1
member_roles_002:
  id: 2
  role_id: 1
  member_id: 2
member_roles_003:
  id: 3
  role_id: 1
  member_id: 3
member_roles_004:
  id: 4
  role_id: 6
  member_id: 4


================================================
FILE: test/fixtures/3.0/members.yml
================================================
---
members_001:
  created_on: 2006-07-19 19:35:33 +02:00
  project_id: 1
  id: 1
  user_id: 1
  mail_notification: true
members_002:
  created_on: 2006-07-19 19:35:36 +02:00
  project_id: 2
  id: 2
  user_id: 1
  mail_notification: true
members_003:
  created_on: 2006-07-19 19:35:36 +02:00
  project_id: 3
  id: 3
  user_id: 1
  mail_notification: true
members_004:
  created_on: 2006-07-19 19:35:36 +02:00
  project_id: 2
  id: 4
  user_id: 2
  mail_notification: false
members_005:
  created_on: 2006-07-19 19:35:36 +02:00
  project_id: 4
  id: 5
  user_id: 1
  mail_notification: true


================================================
FILE: test/fixtures/3.0/projects.yml
================================================
---
projects_001:
  created_on: 2015-03-05 19:13:59 +02:00
  name: Helpdesk Project 1
  updated_on: 2015-03-05 22:53:01 +02:00
  id: 1
  description: First helpdesk project
  homepage: ""
  is_public: true
  identifier: helpdesk_project_1
  parent_id:
  lft: 1
  rgt: 2
projects_002:
  created_on: 2015-03-05 19:14:19 +02:00
  name: Helpdesk Project 2
  updated_on: 2015-03-05 19:14:19 +02:00
  id: 2
  description: Second helpdesk project
  homepage: ""
  is_public: false
  identifier: helpdesk_project_2
  parent_id:
  lft: 3
  rgt: 4
projects_003:
  created_on: 2015-03-05 19:15:21 +02:00
  name: Irrelevant Project
  updated_on: 2015-03-05 19:18:12 +02:00
  id: 3
  description: Project that has no helpdesk features
  homepage: ""
  is_public: true
  identifier: irrelevant_project
  parent_id:
  lft: 5
  rgt: 6
projects_004:
  created_on: 2015-03-05 19:14:19 +02:00
  name: Helpdesk Project 4
  updated_on: 2015-03-05 19:14:19 +02:00
  id: 4
  description: Disabled copy-to helpdesk project
  homepage: ""
  is_public: true
  identifier: helpdesk_project_4
  parent_id:
  lft: 6
  rgt: 7



================================================
FILE: test/fixtures/3.0/projects_trackers.yml
================================================
---
projects_trackers_001:
  project_id: 1
  tracker_id: 1
projects_trackers_002:
  project_id: 1
  tracker_id: 2
projects_trackers_003:
  project_id: 1
  tracker_id: 3
projects_trackers_004:
  project_id: 2
  tracker_id: 1
projects_trackers_005:
  project_id: 2
  tracker_id: 2
projects_trackers_006:
  project_id: 2
  tracker_id: 3
projects_trackers_007:
  project_id: 3
  tracker_id: 1
projects_trackers_008:
  project_id: 3
  tracker_id: 2
projects_trackers_009:
  project_id: 3
  tracker_id: 3
projects_trackers_010:
  project_id: 4
  tracker_id: 1
projects_trackers_011:
  project_id: 4
  tracker_id: 2
projects_trackers_012:
  project_id: 4
  tracker_id: 3


================================================
FILE: test/fixtures/3.0/roles.yml
================================================
---
roles_001:
  name: Manager
  id: 1
  builtin: 0
  issues_visibility: all
  permissions: |
    ---
    - :add_project
    - :edit_project
    - :close_project
    - :select_project_modules
    - :manage_members
    - :manage_versions
    - :manage_categories
    - :view_issues
    - :add_issues
    - :edit_issues
    - :manage_issue_relations
    - :manage_subtasks
    - :add_issue_notes
    - :move_issues
    - :delete_issues
    - :view_issue_watchers
    - :add_issue_watchers
    - :set_issues_private
    - :set_notes_private
    - :view_private_notes
    - :delete_issue_watchers
    - :manage_public_queries
    - :save_queries
    - :view_gantt
    - :view_calendar
    - :log_time
    - :view_time_entries
    - :edit_time_entries
    - :delete_time_entries
    - :manage_news
    - :comment_news
    - :view_documents
    - :add_documents
    - :edit_documents
    - :delete_documents
    - :view_wiki_pages
    - :export_wiki_pages
    - :view_wiki_edits
    - :edit_wiki_pages
    - :delete_wiki_pages_attachments
    - :protect_wiki_pages
    - :delete_wiki_pages
    - :rename_wiki_pages
    - :add_messages
    - :edit_messages
    - :delete_messages
    - :manage_boards
    - :view_files
    - :manage_files
    - :browse_repository
    - :manage_repository
    - :view_changesets
    - :manage_related_issues
    - :manage_project_activities

  position: 1
roles_002:
  name: Developer
  id: 2
  builtin: 0
  issues_visibility: default
  permissions: |
    ---
    - :edit_project
    - :manage_members
    - :manage_versions
    - :manage_categories
    - :view_issues
    - :add_issues
    - :edit_issues
    - :manage_issue_relations
    - :manage_subtasks
    - :add_issue_notes
    - :move_issues
    - :delete_issues
    - :view_issue_watchers
    - :save_queries
    - :view_gantt
    - :view_calendar
    - :log_time
    - :view_time_entries
    - :edit_own_time_entries
    - :manage_news
    - :comment_news
    - :view_documents
    - :add_documents
    - :edit_documents
    - :delete_documents
    - :view_wiki_pages
    - :view_wiki_edits
    - :edit_wiki_pages
    - :protect_wiki_pages
    - :delete_wiki_pages
    - :add_messages
    - :edit_own_messages
    - :delete_own_messages
    - :manage_boards
    - :view_files
    - :manage_files
    - :browse_repository
    - :view_changesets

  position: 2
roles_003:
  name: Reporter
  id: 3
  builtin: 0
  issues_visibility: default
  permissions: |
    ---
    - :edit_project
    - :manage_members
    - :manage_versions
    - :manage_categories
    - :view_issues
    - :add_issues
    - :edit_issues
    - :manage_issue_relations
    - :add_issue_notes
    - :move_issues
    - :view_issue_watchers
    - :save_queries
    - :view_gantt
    - :view_calendar
    - :log_time
    - :view_time_entries
    - :manage_news
    - :comment_news
    - :view_documents
    - :add_documents
    - :edit_documents
    - :delete_documents
    - :view_wiki_pages
    - :view_wiki_edits
    - :edit_wiki_pages
    - :delete_wiki_pages
    - :add_messages
    - :manage_boards
    - :view_files
    - :manage_files
    - :browse_repository
    - :view_changesets

  position: 3
roles_004:
  name: Non member
  id: 4
  builtin: 1
  issues_visibility: default
  permissions: |
    ---
    - :view_issues
    - :add_issues
    - :edit_issues
    - :manage_issue_relations
    - :add_issue_notes
    - :save_queries
    - :view_gantt
    - :view_calendar
    - :log_time
    - :view_time_entries
    - :comment_news
    - :view_documents
    - :view_wiki_pages
    - :view_wiki_edits
    - :edit_wiki_pages
    - :add_messages
    - :view_files
    - :manage_files
    - :browse_repository
    - :view_changesets

  position: 4
roles_005:
  name: Anonymous
  id: 5
  builtin: 2
  issues_visibility: default
  permissions: |
    ---
    - :treat_user_as_supportclient
    - :view_issues
    - :add_issue_notes
    - :view_gantt
    - :view_calendar
    - :view_time_entries
    - :view_documents
    - :view_wiki_pages
    - :view_wiki_edits
    - :view_files
    - :browse_repository
    - :view_changesets

  position: 5
roles_006:
  name: SupportClient
  id: 6
  builtin: 0
  issues_visibility: default
  permissions: |
    ---
    - :treat_user_as_supportclient
    - :add_issues
    - :add_issue_notes
  position: 6


================================================
FILE: test/fixtures/3.0/trackers.yml
================================================
---
trackers_001:
  name: Bug
  id: 1
  is_in_chlog: true
  position: 1
  default_status_id: 1
trackers_002:
  name: Feature request
  id: 2
  is_in_chlog: true
  position: 2
  default_status_id: 1
trackers_003:
  name: Support request
  id: 3
  is_in_chlog: false
  position: 3
  default_status_id: 1


================================================
FILE: test/fixtures/3.0/users.yml
================================================
---
users_001:
  created_on: 2015-03-05 19:34:07 +02:00
  status: 1
  last_login_on:
  language: en
  # password = foo
  salt: 3126f764c3c5ac61cbfc103f25f934cf
  hashed_password: 9e4dd7eeb172c12a0691a6d9d3a269f7e9fe671b
  updated_on: 2015-03-05 19:34:07 +02:00
  admin: true
  lastname: Hill
  firstname: Robert
  id: 1
  auth_source_id:
  mail_notification: all
  login: normaluser
  type: User
users_002:
  created_on: 2015-03-05 19:33:19 +02:00
  status: 1
  last_login_on:
  language: en
  # password = foo
  salt: 7599f9963ec07b5a3b55b354407120c0
  hashed_password: 8f659c8d7c072f189374edacfa90d6abbc26d8ed
  updated_on: 2015-03-05 19:33:19 +02:00
  admin: false
  lastname: Lopper
  firstname: Dave
  id: 2
  auth_source_id:
  mail_notification: all
  login: supportclient
  type: User
users_003:
  id: 3
  created_on: 2006-07-19 19:33:19 +02:00
  status: 0
  last_login_on:
  language: ''
  hashed_password: 1
  updated_on: 2006-07-19 19:33:19 +02:00
  admin: false
  lastname: Anonymous
  firstname: ''
  auth_source_id:
  mail_notification: only_my_events
  login: ''
  type: AnonymousUser


================================================
FILE: test/fixtures/files/2006/07/060719210727_source.rb
================================================
# The Greeter class
class Greeter
  def initialize(name)
    @name = name.capitalize
  end

  def salute
    puts "Hello #{@name}!" 
  end
end


================================================
FILE: test/fixtures/mail_handler/ticket_by_unknown_user.eml
================================================
Return-Path: <john.doe@somenet.foo>
Received: from osiris ([127.0.0.1])
	by OSIRIS
	with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200
Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris>
From: "John Doe" <john.doe@somenet.foo>
To: <redmine@somenet.foo>
Subject: Ticket by unknown user
Date: Sun, 22 Jun 2008 12:28:07 +0200
MIME-Version: 1.0
Content-Type: text/plain;
	format=flowed;
	charset="iso-8859-1";
	reply-type=original
Content-Transfer-Encoding: 7bit

This is a ticket submitted by an unknown user.



================================================
FILE: test/fixtures/mail_handler/ticket_by_unknown_user_with_cc.eml
================================================
Return-Path: <john.doe@somenet.foo>
Received: from osiris ([127.0.0.1])
	by OSIRIS
	with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200
Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris>
From: "John Doe" <john.doe@somenet.foo>
To: <redmine@somenet.foo>
Cc: "Ada" <ada@test.lindsaar.net>, My Group: <mikel@test.lindsaar.net>, Bob <bob@test.lindsaar.net>;
Subject: Ticket by unknown user
Date: Sun, 22 Jun 2008 12:28:07 +0200
MIME-Version: 1.0
Content-Type: text/plain;
	format=flowed;
	charset="iso-8859-1";
	reply-type=original
Content-Transfer-Encoding: 7bit

This is a ticket submitted by an unknown user with cc.



================================================
FILE: test/fixtures/mail_handler/ticket_by_user_1.eml
================================================
Return-Path: <rhill@somenet.foo>
Received: from osiris ([127.0.0.1])
	by OSIRIS
	with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200
Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris>
From: "John Doe" <rhill@somenet.foo>
To: <redmine@somenet.foo>
Subject: Ticket by unknown user
Date: Sun, 22 Jun 2008 12:28:07 +0200
MIME-Version: 1.0
Content-Type: text/plain;
	format=flowed;
	charset="iso-8859-1";
	reply-type=original
Content-Transfer-Encoding: 7bit

This is a ticket submitted by an unknown user.



================================================
FILE: test/fixtures/mail_handler/ticket_by_user_2.eml
================================================
Return-Path: <dlopper@somenet.foo>
Received: from osiris ([127.0.0.1])
	by OSIRIS
	with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200
Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris>
From: "John Doe" <dlopper@somenet.foo>
To: <redmine@somenet.foo>
Subject: Ticket by unknown user
Date: Sun, 22 Jun 2008 12:28:07 +0200
MIME-Version: 1.0
Content-Type: text/plain;
	format=flowed;
	charset="iso-8859-1";
	reply-type=original
Content-Transfer-Encoding: 7bit

This is a ticket submitted by an unknown user.



================================================
FILE: test/fixtures/mail_handler/ticket_reply.eml
================================================
Return-Path: <jsmith@somenet.foo>
Received: from osiris ([127.0.0.1])
	by OSIRIS
	with hMailServer ; Sat, 21 Jun 2008 18:41:39 +0200
Message-ID: <006a01c8d3bd$ad9baec0$0a00a8c0@osiris>
In-Reply-To: <redmine.issue-2.20060719210421@osiris>
From: "John Smith" <jsmith@somenet.foo>
To: <redmine@somenet.foo>
References: <485d0ad366c88_d7014663a025f@osiris.tmail>
Subject: Re: Add ingredients categories
Date: Sat, 21 Jun 2008 18:41:39 +0200
MIME-Version: 1.0
Content-Type: multipart/alternative;
	boundary="----=_NextPart_000_0067_01C8D3CE.711F9CC0"
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 6.00.2900.2869
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869

This is a multi-part message in MIME format.

------=_NextPart_000_0067_01C8D3CE.711F9CC0
Content-Type: text/plain;
	charset="utf-8"
Content-Transfer-Encoding: quoted-printable

This is reply
------=_NextPart_000_0067_01C8D3CE.711F9CC0
Content-Type: text/html;
	charset="utf-8"
Content-Transfer-Encoding: quoted-printable

=EF=BB=BF<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; charset=3Dutf-8">
<STYLE>BODY {
	FONT-SIZE: 0.8em; COLOR: #484848; FONT-FAMILY: Verdana, sans-serif
}
BODY H1 {
	FONT-SIZE: 1.2em; MARGIN: 0px; FONT-FAMILY: "Trebuchet MS", Verdana, =
sans-serif
}
A {
	COLOR: #2a5685
}
A:link {
	COLOR: #2a5685
}
A:visited {
	COLOR: #2a5685
}
A:hover {
	COLOR: #c61a1a
}
A:active {
	COLOR: #c61a1a
}
HR {
	BORDER-RIGHT: 0px; BORDER-TOP: 0px; BACKGROUND: #ccc; BORDER-LEFT: 0px; =
WIDTH: 100%; BORDER-BOTTOM: 0px; HEIGHT: 1px
}
.footer {
	FONT-SIZE: 0.8em; FONT-STYLE: italic
}
</STYLE>

<META content=3D"MSHTML 6.00.2900.2883" name=3DGENERATOR></HEAD>
<BODY bgColor=3D#ffffff>
<DIV><SPAN class=3Dfooter><FONT face=3DArial color=3D#000000 =
size=3D2>This is=20
reply</FONT></DIV></SPAN></BODY></HTML>

------=_NextPart_000_0067_01C8D3CE.711F9CC0--



================================================
FILE: test/fixtures/mail_handler/ticket_with_attachment.eml
================================================
Return-Path: <jsmith@somenet.foo>
Received: from osiris ([127.0.0.1])
	by OSIRIS
	with hMailServer ; Sat, 21 Jun 2008 15:53:25 +0200
Message-ID: <002301c8d3a6$2cdf6950$0a00a8c0@osiris>
From: "John Smith" <jsmith@somenet.foo>
To: <redmine@somenet.foo>
Subject: Ticket created by email with attachment
Date: Sat, 21 Jun 2008 15:53:25 +0200
MIME-Version: 1.0
Content-Type: multipart/mixed;
	boundary="----=_NextPart_000_001F_01C8D3B6.F05C5270"
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 6.00.2900.2869
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869

This is a multi-part message in MIME format.

------=_NextPart_000_001F_01C8D3B6.F05C5270
Content-Type: multipart/alternative;
	boundary="----=_NextPart_001_0020_01C8D3B6.F05C5270"


------=_NextPart_001_0020_01C8D3B6.F05C5270
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

This is  a new ticket with attachments
------=_NextPart_001_0020_01C8D3B6.F05C5270
Content-Type: text/html;
	charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2900.2883" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=3D#ffffff>
<DIV><FONT face=3DArial size=3D2>This is&nbsp; a new ticket with=20
attachments</FONT></DIV></BODY></HTML>

------=_NextPart_001_0020_01C8D3B6.F05C5270--

------=_NextPart_000_001F_01C8D3B6.F05C5270
Content-Type: image/jpeg;
	name="Paella.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
	filename="Paella.jpg"

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
cbis+/WpUqUcMZKdF44n/9k=

------=_NextPart_000_001F_01C8D3B6.F05C5270--



================================================
FILE: test/fixtures/mail_handler/ticket_with_attributes.eml
================================================
Return-Path: <jsmith@somenet.foo>
Received: from osiris ([127.0.0.1])
	by OSIRIS
	with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200
Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris>
From: "John Smith" <jsmith@somenet.foo>
To: <redmine@somenet.foo>
Subject: New ticket on a given project
Date: Sun, 22 Jun 2008 12:28:07 +0200
MIME-Version: 1.0
Content-Type: text/plain;
	format=flowed;
	charset="iso-8859-1";
	reply-type=original
Content-Transfer-Encoding: 7bit
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 6.00.2900.2869
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet 
turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus 
blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti 
sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In 
in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras 
sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum 
id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus 
eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique 
sed, mauris. Pellentesque habitant morbi tristique senectus et netus et 
malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse 
platea dictumst.

Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque 
sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem. 
Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et, 
dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed, 
massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo 
pulvinar dui, a gravida orci mi eget odio. Nunc a lacus.

Project: onlinestore
Tracker: Feature Request
category: stock management
priority: URGENT


================================================
FILE: test/functional/issues_controller_with_helpdesk_test.rb
================================================
require File.dirname(__FILE__) + '/../test_helper'

class IssuesControllerWithHelpdeskTest < ActionController::TestCase
  include Redmine::I18n

  fixtures :all

  def setup
    User.current = nil
    @controller = IssuesController.new
  end

  def test_render_send_to_owner_checkbox
    issue = Issue.find(1)
    @request.session[:user_id] = 1
    get :edit, :id => 1
    assert_response :success
    assert_select "#send_to_owner", 1
  end

  test "send_to_owner not renderer without owner-email" do
    issue = Issue.find(1)
    owner_field = CustomField.find_by_name('owner-email')
    owner_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.id, owner_field.id).
      first
    owner_value.value = ""
    owner_value.save!

    @request.session[:user_id] = 1
    get :edit, :id => 1
    assert_response :success
    assert_select "#send_to_owner", 0
  end

  test "send_to_owner checked if send-to-owner-default is set to yes" do
    issue = Issue.find(1)
    default_field = CustomField.find_by_name('helpdesk-send-to-owner-default')
    default_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, default_field.id).
      first
    default_value.value = "1"
    default_value.save!

    @request.session[:user_id] = 1
    get :edit, :id => 1
    assert_response :success
    assert_select "#send_to_owner", 1
    assert_equal "checked", css_select("#send_to_owner").first["checked"]
  end

  test "send_to_owner checked if send-to-owner-default is set to no" do
    issue = Issue.find(1)
    default_field = CustomField.find_by_name('helpdesk-send-to-owner-default')
    default_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, default_field.id).
      first
    default_value.value = "2"
    default_value.save!

    @request.session[:user_id] = 1
    get :edit, :id => 1
    assert_response :success
    assert_select "#send_to_owner", 1
    assert_not_equal "checked", css_select("#send_to_owner").first["checked"]
  end

  test "history note added to journal if note has been sent to owner" do
    issue = Issue.find(1)
    journal = issue.journals.first
    journal.send_to_owner = true
    journal.save

    @request.session[:user_id] = 1
    get :show, :id => 1
    assert_response :success

    assert_select "#history>i", 1
    assert_select "#history>i", "This answer was sent to the supportclient."
  end

  test "history note not added to journal if note has not been sent to owner" do
    issue = Issue.find(1)
    journal = issue.journals.first
    journal.send_to_owner = false
    journal.save

    @request.session[:user_id] = 1
    get :show, :id => 1
    assert_response :success

    assert_select "#history>i", 0
  end

  test "send_to_owner checked" do
    ActionMailer::Base.delivery_method = :test
    ActionMailer::Base.deliveries.clear
    @request.session[:user_id] = 1
    assert_difference('Journal.count') do
      put :update, :id => 1,
                   :issue => {:assigned_to_id => 1,
                              :notes => 'Assigned'},
                   :send_to_owner => "true"
    end
    assert_redirected_to :action => 'show', :id => '1'

    assert Issue.find(1).journals.last.send_to_owner
    mail = ActionMailer::Base.deliveries.last
    assert_equal "owner@example.com",  mail.to.first
    assert_equal "Assigned\n\nemail footer", mail.body.to_s
  end

  test "send_to_owner not checked" do
    ActionMailer::Base.delivery_method = :test
    ActionMailer::Base.deliveries.clear
    @request.session[:user_id] = 1
    assert_difference('Journal.count') do
      put :update, :id => 1,
                   :issue => {:assigned_to_id => 1,
                              :notes => 'Assigned'},
                   :send_to_owner => "false"
    end
    assert_redirected_to :action => 'show', :id => '1'

    assert !Issue.find(1).journals.last.send_to_owner
    ActionMailer::Base.deliveries.each do |mail|
      assert !mail.to.include?("owner@example.com")
    end
  end
end


================================================
FILE: test/test_helper.rb
================================================
require "simplecov"
require "codeclimate-test-reporter"

SimpleCov.use_merging true
SimpleCov.merge_timeout 3600
SimpleCov.add_filter '/test/'
SimpleCov.add_filter 'init.rb'
SimpleCov.formatters = []
SimpleCov.start(CodeClimate::TestReporter.configuration.profile) do
  root File.expand_path(File.dirname(__FILE__) + '/../../')
end

# Load the normal Rails helper
require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper')

class TestHelper
  def self.files_path
    File.dirname(__FILE__) + '/fixtures/'
  end
  def self.fixture_path
    if Redmine::VERSION::MAJOR >= 3
      File.dirname(__FILE__) + '/fixtures/3.0'
    else
      File.dirname(__FILE__) + '/fixtures/2.6'
    end
  end
end

class ActiveSupport::TestCase
  self.fixture_path = TestHelper.fixture_path
end


================================================
FILE: test/unit/helpdesk_mailer_test.rb
================================================
require File.dirname(__FILE__) + '/../test_helper'

class HelpdeskMailerTest < ActionMailer::TestCase
  include Redmine::I18n

  self.use_transactional_tests = true

  fixtures :all

  def setup
    ActionMailer::Base.deliveries.clear
    Setting.host_name = 'mydomain.foo'
    Setting.protocol = 'http'
    Setting.plain_text_mail = '0'
    Setting.default_language = 'en'
    User.current = nil
  end

  def teardown
    Setting.clear_cache
  end

  def test_default_url_options
    default_url_object = HelpdeskMailer.default_url_options
    assert_equal "mydomain.foo", default_url_object[:host]
    assert_equal "http", default_url_object[:protocol]
  end

  def test_email_headers
    issue = Issue.find(1)
    email = HelpdeskMailer.
        email_to_supportclient(issue, {:recipient => "owner@example.com"}).
        deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert_not_nil email
    assert_equal issue.project.identifier, email.header['X-Redmine-Project'].to_s
    assert_equal issue.id, email.header['X-Redmine-Issue-Id'].to_s.to_i
    assert_equal issue.author.login, email.header['X-Redmine-Issue-Author'].to_s
    assert_equal issue.assigned_to.login, email.header['X-Redmine-Issue-Assignee'].to_s
    assert_equal issue.tracker, email.header['X-Redmine-Issue-Tracker'].to_s

    #assert_equal 'OOF', mail.header['X-Auto-Response-Suppress'].to_s
    #assert_equal 'auto-generated', mail.header['Auto-Submitted'].to_s
    #assert_equal '<redmine.example.net>', mail.header['List-Id'].to_s
  end

  def test_email_default_sender
    issue = Issue.find(1)
    s = CustomField.find_by_name('helpdesk-sender-email')
    custom_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, s.id).
      first
    custom_value.destroy

    email = HelpdeskMailer.
        email_to_supportclient(issue, {:recipient => "owner@example.com"}).
        deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert_equal Setting.mail_from, email.header['From'].to_s
  end

  def test_email_helpdesk_sender
    issue = Issue.find(1)
    email = HelpdeskMailer.
        email_to_supportclient(issue, {:recipient => "owner@example.com"}).
        deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert_equal "reply@example.com", email.header['From'].to_s
  end

  def test_email_helpdesk_sender_with_phrase
    issue = Issue.find(1)
    s = CustomField.find_by_name('helpdesk-sender-email')
    custom_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, s.id).
      first
    custom_value.value = "Redmine helpdesk <reply@example.com>"
    custom_value.save

    email = HelpdeskMailer.
        email_to_supportclient(issue, {:recipient => "owner@example.com"}).deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert_equal "Redmine helpdesk <reply@example.com>", email.header['From'].to_s
  end

  def test_first_reply
    issue = Issue.find(1)
    email = HelpdeskMailer.
        email_to_supportclient(issue, {:recipient => "owner@example.com"}).
        deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert_match /^redmine\.issue-1\.\d+\.[a-f0-9]+@example\.net/, email.message_id
    assert_match /redmine\.issue-1\.\d+@example\.net/, email.references

    assert_equal "first reply",
        email.body.to_s
  end

  def test_edit
    issue = Issue.find(1)
    email = HelpdeskMailer.
        email_to_supportclient(
            issue,
            {:recipient => "owner@example.com",
             :journal   => Journal.find(1),
             :text     => 'text'
            }).
        deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert_match /^redmine\.issue-1\.\d+\.[a-f0-9]+@example\.net/, email.message_id
    assert_match /redmine\.issue-1\.\d+@example\.net/, email.references

    assert_equal "text\n\nemail footer",
        email.body.to_s
  end

  def test_fallback_message_id
    issue = Issue.find(2)
    s = CustomField.find_by_name('helpdesk-first-reply')
    custom_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, s.id).
      first
    custom_value.destroy

    email = HelpdeskMailer.
        email_to_supportclient(
            issue,
            {:recipient => "owner@example.com",
             :journal   => Journal.find(1),
             :text      => 'text'
            }).
        deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert_match /^redmine\.issue-2\.\d+\.[a-f0-9]+@example\.net/, email.message_id
    assert_match /redmine\.issue-2\.\d+@example\.net/, email.references
  end

  def test_subject
    issue = Issue.find(1)
    email = HelpdeskMailer.
        email_to_supportclient(issue, {:recipient => "owner_email"}).
        deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert_equal "[#{issue.project.name} - ##{issue.id}] #{issue.subject}", email.subject.to_s
  end

  # Test with single attachment and verify against fixture file
  def test_attachments_added
    Attachment.storage_path = TestHelper.files_path + '/files'
    issue = Issue.find(1)
    email = HelpdeskMailer.
        email_to_supportclient(
            issue,
            {:recipient => "owner@example.com",
             :journal   => Journal.find(3),
             :text      => 'text'
            }).deliver
    assert !ActionMailer::Base.deliveries.empty?
    mail = ActionMailer::Base.deliveries.last
    assert_not_nil mail
    attachments_length = mail.attachments.length
    assert_equal 1, attachments_length
    filename = mail.attachments[0].filename
    assert_equal "source.rb", filename
    content = mail.attachments[0].body.to_s
    original_content = File.open(
        Attachment.find(
            Journal.find(3).details.first.prop_key).diskfile).read
    assert_equal original_content, content
  end
end


================================================
FILE: test/unit/journal_patch_test.rb
================================================
require File.dirname(__FILE__) + '/../test_helper'

class JournalPatchTest < ActiveSupport::TestCase
  include Redmine::I18n

  self.use_transactional_tests = true

  fixtures :all

  def setup
    User.current = User.find(1)
  end

  def teardown
    Setting.clear_cache
  end

  def test_notification_not_sent_when_send_to_owner_false
    HelpdeskMailer.any_instance.expects(:email_to_supportclient).never
    Mailer.any_instance.stubs(:deliver_issue_edit).returns(true)

    issue = Issue.find(1)
    journal = issue.journals.first
    journal.send_to_owner = false
    journal.save!

    journal.send(:send_notification)
  end

  def test_notification_not_sent_when_notes_length_zero
    HelpdeskMailer.any_instance.expects(:email_to_supportclient).never
    Mailer.any_instance.stubs(:deliver_issue_edit).returns(true)

    issue = Issue.find(1)
    journal = issue.journals.first
    journal.notes = ""
    journal.send_to_owner = true
    journal.save!

    journal.send(:send_notification)
  end

  def test_notification_note_sent_when_owner_email_blank
    HelpdeskMailer.any_instance.expects(:email_to_supportclient).never
    Mailer.any_instance.stubs(:deliver_issue_edit).returns(true)

    issue = Issue.find(1)
    journal = issue.journals.first
    owner_field = CustomField.find_by_name('owner-email')
    owner_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.id, owner_field.id).
      first
    owner_value.value = ""
    owner_value.save!
    journal.send_to_owner = true
    journal.save!

    journal.send(:send_notification)
  end

  def test_notification_sent
    Mailer.any_instance.stubs(:deliver_issue_edit).returns(true)

    issue = Issue.find(1)
    journal = issue.journals.first
    journal.send_to_owner = true
    journal.save!

    HelpdeskMailer.any_instance.expects(:email_to_supportclient).with(issue, 
        {:recipient => "owner@example.com", 
         :journal   => journal, 
         :text      => journal.notes
        }).once
    journal.send(:send_notification)
  end
end


================================================
FILE: test/unit/macro_expander_test.rb
================================================
require File.dirname(__FILE__) + '/../test_helper'

class MacroExpanderTest < ActionMailer::TestCase
  include Redmine::I18n

  self.use_transactional_tests = true

  fixtures :all

  def setup
    ActionMailer::Base.deliveries.clear
    Setting.host_name = 'mydomain.foo'
    Setting.protocol = 'http'
    Setting.plain_text_mail = '0'
    Setting.default_language = 'en'
    User.current = nil
  end

  def teardown
    Setting.clear_cache
  end

  def test_expand_issue
    issue = Issue.find(1)
    s = CustomField.find_by_name('helpdesk-email-footer')
    custom_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, s.id).
      first
    custom_value.value = "##issue-id##, ##issue-subject##, ##issue-tracker##, ##issue-status##"
    custom_value.save
    email = HelpdeskMailer.
        email_to_supportclient(
            issue,
            {
                :recipient => "owner@example.com",
                :journal   => Journal.find(1),
                :text      => 'text'
            }).deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert "text\n\n#{issue.id}, #{issue.subject}, #{issue.tracker}, #{issue.status}", email.body.to_s
  end

  def test_expand_project
    issue = Issue.find(1)
    s = CustomField.find_by_name('helpdesk-email-footer')
    custom_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, s.id).
      first
    custom_value.value = "##project-name##"
    custom_value.save
    email = HelpdeskMailer.
        email_to_supportclient(
            issue,
            { 
                :recipient => "owner@example.com",
                :journal   => Journal.find(1),
                :text      =>'text'
            }).deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert "text\n\n#{issue.project.name}", email.body.to_s
  end

  def test_expand_user
    issue = Issue.find(1)
    s = CustomField.find_by_name('helpdesk-email-footer')
    custom_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, s.id).
      first
    custom_value.value = "##user-name##, ##user-firstname##, ##user-lastname##, ##user-mail##, ##user-login##"
    custom_value.save
    email = HelpdeskMailer.
        email_to_supportclient(
            issue,
            {
                :recipient => "owner@example.com",
                :journal   => Journal.find(1),
                :text      => 'text'
            }).deliver
    assert !ActionMailer::Base.deliveries.empty?
    user = Journal.find(1).user
    assert "text\n\n#{user.name}, #{user.firstname}, #{user.lastname}, #{user.mail}, #{user.login}", email.body.to_s
  end

  def test_expand_user_cfs_w_not_existing
    issue = Issue.find(1)
    user = Journal.find(1).user
    s = CustomField.find_by_name('helpdesk-email-footer')
    custom_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, s.id).
      first
    custom_value.value = "##user-cf-title##, ##user-cf-motto##, ##user-cf-invalid##."
    custom_value.save

    title = CustomField.find_by_name('title')
    custom_value = CustomValue.new(
      :customized_id => user.id,
      :custom_field_id => title.id,
      :value => "junior senior"
    )
    custom_value.save
    motto = CustomField.find_by_name('motto')
    custom_value = CustomValue.new(
      :customized_id => user.id,
      :custom_field_id => motto.id,
      :value => "epic motto"
    )
    custom_value.save

    email = HelpdeskMailer.
        email_to_supportclient(
            issue,
            {:recipient => "owner@example.com",
             :journal   => Journal.find(1),
             :text      =>'text'
            }).deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert "text\n\njunior senior, epic motto, .", email.body.to_s
  end

  def test_expand_user_no_cfs
    issue = Issue.find(1)
    user = Journal.find(1).user
    s = CustomField.find_by_name('helpdesk-email-footer')
    custom_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, s.id).
      first
    custom_value.value = "##user-cf-title##, ##user-cf-motto##, ##user-cf-invalid##."
    custom_value.save

    email = HelpdeskMailer.
        email_to_supportclient(
            issue,
            {
                :recipient => "owner@example.com",
                :journal   => Journal.find(1),
                :text      => 'text'
            }).deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert "text\n\n, , .", email.body.to_s
  end

  def test_expand_base
    issue = Issue.find(1)
    s = CustomField.find_by_name('helpdesk-email-footer')
    custom_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.project.id, s.id).
      first
    custom_value.value = "##time-now##"
    custom_value.save

    t1 = I18n.l(Time.zone.now)
    email = HelpdeskMailer.
        email_to_supportclient(
            issue,
            {
                :recipient => "owner@example.com",
                :journal   => Journal.find(1),
                :text      => 'text'
            }).deliver
    assert !ActionMailer::Base.deliveries.empty?
    assert "text\n\n#{t1}", email.body.to_s
  end
end


================================================
FILE: test/unit/mail_handler_patch_test.rb
================================================
require File.dirname(__FILE__) + '/../test_helper'

class MailHandlerPatchTest < ActiveSupport::TestCase
  include Redmine::I18n

  self.use_transactional_tests = true

  fixtures :all

  def setup
    ActionMailer::Base.deliveries.clear
    Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
  end

  def teardown
    Setting.clear_cache
  end

  def test_helpdesk_dispatch_not_supportclient
    HelpdeskMailer.any_instance.expects(:email_to_supportclient).never
    issue = submit_email('ticket_by_user_1.eml',
                         :issue => {:project => 'helpdesk_project_1'},
                         :unknown_user => 'accept',
                         :no_permission_check => 1)
    assert_issue_created issue

    owner_field = CustomField.find_by_name('owner-email')
    owner_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.id, owner_field.id).
      first
    assert owner_value.value.blank?
    assert User.find(1).login, issue.author.login
  end

  def test_helpdesk_dispatch_disabled_copy_to
    assert_no_difference 'User.count' do
      HelpdeskMailer.any_instance.expects(:email_to_supportclient).with(
        kind_of(Issue),  {:recipient =>"john.doe@somenet.foo", 
                          :carbon_copy => nil}
      ).once
      issue = submit_email('ticket_by_unknown_user_with_cc.eml',
                       :issue => {:project => 'helpdesk_project_4'},
                       :unknown_user => 'accept',
                       :no_permission_check => 1)
      assert_issue_created issue

      owner_field = CustomField.find_by_name('owner-email')
      owner_value = CustomValue.where(
          "customized_id = ? AND custom_field_id = ?", issue.id, owner_field.id).
          first
      assert_equal "john.doe@somenet.foo", owner_value.value
      assert issue.author.anonymous?
    end
  end

  def test_helpdesk_dispatch_anonymous_as_supportclient
    assert_no_difference 'User.count' do
      HelpdeskMailer.any_instance.expects(:email_to_supportclient).with(
        kind_of(Issue), {:recipient =>"john.doe@somenet.foo", :carbon_copy => nil}).once
      issue = submit_email('ticket_by_unknown_user.eml',
                       :issue => {:project => 'helpdesk_project_1'},
                       :unknown_user => 'accept',
                       :no_permission_check => 1)
      assert_issue_created issue

      owner_field = CustomField.find_by_name('owner-email')
      owner_value = CustomValue.where(
          "customized_id = ? AND custom_field_id = ?", issue.id, owner_field.id).
          first
      assert_equal "john.doe@somenet.foo", owner_value.value
      assert issue.author.anonymous?
    end
  end

  def test_helpdesk_dispatch_anonymous_as_supportclient_with_cc
    assert_no_difference 'User.count' do
      HelpdeskMailer.any_instance.expects(:email_to_supportclient).with(
        kind_of(Issue),  {:recipient =>"john.doe@somenet.foo", 
                          :carbon_copy => "Ada <ada@test.lindsaar.net>, mikel@test.lindsaar.net, Bob <bob@test.lindsaar.net>"}
      ).once
      issue = submit_email('ticket_by_unknown_user_with_cc.eml',
                       :issue => {:project => 'helpdesk_project_1'},
                       :unknown_user => 'accept',
                       :no_permission_check => 1)
      assert_issue_created issue

      owner_field = CustomField.find_by_name('owner-email')
      owner_value = CustomValue.where(
          "customized_id = ? AND custom_field_id = ?", issue.id, owner_field.id).
          first
      copy_to_field = CustomField.find_by_name('copy-to')
      copy_to_value = CustomValue.where(
          "customized_id = ? AND custom_field_id = ?", issue.id, copy_to_field.id).
          first
      assert_equal "john.doe@somenet.foo", owner_value.value
      assert issue.author.anonymous?
      assert_equal "Ada <ada@test.lindsaar.net>, mikel@test.lindsaar.net, Bob <bob@test.lindsaar.net>",
          copy_to_value.value
    end
  end

  def test_helpdesk_dispatch_supportclient
    HelpdeskMailer.any_instance.expects(:email_to_supportclient).with(kind_of(Issue), 
        {:recipient => User.find(2).mail, :carbon_copy => nil})
    issue = submit_email('ticket_by_user_2.eml',
                         :issue => {:project => 'helpdesk_project_2'},
                         :unknown_user => 'accept',
                         :no_permission_check => 1)
    assert_issue_created issue

    owner_field = CustomField.find_by_name('owner-email')
    owner_value = CustomValue.where(
      "customized_id = ? AND custom_field_id = ?", issue.id, owner_field.id).
      first
    assert_equal User.find(2).mail, owner_value.value
    assert User.find(2).login, issue.author.login
  end

  # TODO: Attachments

  def submit_email(filename, options={})
    raw = IO.read(File.join(TestHelper.files_path, 'mail_handler', filename))
    yield raw if block_given?
    MailHandler.receive(raw, options)
  end

  def assert_issue_created(issue)
    assert issue.is_a?(Issue)
    assert !issue.new_record?
    issue.reload
  end
end
Download .txt
gitextract_lz5v3in0/

├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── app/
│   └── views/
│       ├── _issue_edit.erb
│       └── _issue_history.erb
├── config/
│   └── locales/
│       ├── de.yml
│       ├── en.yml
│       ├── es.yml
│       ├── it.yml
│       ├── ja.yml
│       ├── pl.yml
│       ├── ru.yml
│       ├── tr.yml
│       └── zh.yml
├── db/
│   └── migrate/
│       ├── 001_create_custom_owner_email_field.rb
│       ├── 002_create_custom_fields_for_reply.rb
│       ├── 003_create_custom_field_for_sender_email.rb
│       ├── 004_create_custom_field_for_send_to_owner_default.rb
│       ├── 005_add_treat_as_supportclient_to_anonymous.rb
│       ├── 006_append_footer_to_first_reply.rb
│       ├── 007_create_custom_copy_to_field.rb
│       ├── 008_create_custom_field_cc_handling.rb
│       ├── 009_create_custom_field_for_reopen_closed_issues_by_email.rb
│       └── 010_create_custom_field_for_reply_separator.rb
├── init.rb
├── lib/
│   ├── helpdesk_hooks.rb
│   ├── helpdesk_mailer.rb
│   ├── macro_expander.rb
│   ├── redmine_helpdesk/
│   │   ├── journal_patch.rb
│   │   ├── mail_handler_patch.rb
│   │   └── mailer_patch.rb
│   └── tasks/
│       ├── local-db.rake
│       ├── plugin_ci.rake
│       └── redmine.rake
└── test/
    ├── confs/
    │   ├── database_mysql.yml
    │   ├── database_postgres.yml
    │   ├── database_postgres_ext.yml
    │   └── database_sqlite.yml
    ├── fixtures/
    │   ├── 2.6/
    │   │   ├── attachments.yml
    │   │   ├── custom_fields.yml
    │   │   ├── custom_fields_projects.yml
    │   │   ├── custom_fields_trackers.yml
    │   │   ├── custom_values.yml
    │   │   ├── enabled_modules.yml
    │   │   ├── enumerations.yml
    │   │   ├── issue_statuses.yml
    │   │   ├── issues.yml
    │   │   ├── journal_details.yml
    │   │   ├── journals.yml
    │   │   ├── member_roles.yml
    │   │   ├── members.yml
    │   │   ├── projects.yml
    │   │   ├── projects_trackers.yml
    │   │   ├── roles.yml
    │   │   ├── trackers.yml
    │   │   └── users.yml
    │   ├── 3.0/
    │   │   ├── attachments.yml
    │   │   ├── custom_fields.yml
    │   │   ├── custom_fields_projects.yml
    │   │   ├── custom_fields_trackers.yml
    │   │   ├── custom_values.yml
    │   │   ├── email_addresses.yml
    │   │   ├── enabled_modules.yml
    │   │   ├── enumerations.yml
    │   │   ├── issue_statuses.yml
    │   │   ├── issues.yml
    │   │   ├── journal_details.yml
    │   │   ├── journals.yml
    │   │   ├── member_roles.yml
    │   │   ├── members.yml
    │   │   ├── projects.yml
    │   │   ├── projects_trackers.yml
    │   │   ├── roles.yml
    │   │   ├── trackers.yml
    │   │   └── users.yml
    │   ├── files/
    │   │   └── 2006/
    │   │       └── 07/
    │   │           └── 060719210727_source.rb
    │   └── mail_handler/
    │       ├── ticket_by_unknown_user.eml
    │       ├── ticket_by_unknown_user_with_cc.eml
    │       ├── ticket_by_user_1.eml
    │       ├── ticket_by_user_2.eml
    │       ├── ticket_reply.eml
    │       ├── ticket_with_attachment.eml
    │       └── ticket_with_attributes.eml
    ├── functional/
    │   └── issues_controller_with_helpdesk_test.rb
    ├── test_helper.rb
    └── unit/
        ├── helpdesk_mailer_test.rb
        ├── journal_patch_test.rb
        ├── macro_expander_test.rb
        └── mail_handler_patch_test.rb
Download .txt
SYMBOL INDEX (124 symbols across 24 files)

FILE: db/migrate/001_create_custom_owner_email_field.rb
  class CreateCustomOwnerEmailField (line 1) | class CreateCustomOwnerEmailField < ActiveRecord::Migration[5.2]
    method up (line 2) | def self.up
    method down (line 19) | def self.down

FILE: db/migrate/002_create_custom_fields_for_reply.rb
  class CreateCustomFieldsForReply (line 1) | class CreateCustomFieldsForReply < ActiveRecord::Migration[5.2]
    method up (line 2) | def self.up
    method down (line 19) | def self.down

FILE: db/migrate/003_create_custom_field_for_sender_email.rb
  class CreateCustomFieldForSenderEmail (line 1) | class CreateCustomFieldForSenderEmail < ActiveRecord::Migration[5.2]
    method up (line 2) | def self.up
    method down (line 12) | def self.down

FILE: db/migrate/004_create_custom_field_for_send_to_owner_default.rb
  class CreateCustomFieldForSendToOwnerDefault (line 1) | class CreateCustomFieldForSendToOwnerDefault < ActiveRecord::Migration[5.2]
    method up (line 2) | def self.up
    method down (line 12) | def self.down

FILE: db/migrate/005_add_treat_as_supportclient_to_anonymous.rb
  class AddTreatAsSupportclientToAnonymous (line 1) | class AddTreatAsSupportclientToAnonymous < ActiveRecord::Migration[5.2]
    method up (line 2) | def self.up
    method down (line 10) | def self.down

FILE: db/migrate/006_append_footer_to_first_reply.rb
  class AppendFooterToFirstReply (line 1) | class AppendFooterToFirstReply < ActiveRecord::Migration[5.2]
    method up (line 5) | def self.up

FILE: db/migrate/007_create_custom_copy_to_field.rb
  class CreateCustomCopyToField (line 1) | class CreateCustomCopyToField < ActiveRecord::Migration[5.2]
    method up (line 2) | def self.up
    method down (line 14) | def self.down

FILE: db/migrate/008_create_custom_field_cc_handling.rb
  class CreateCustomFieldCcHandling (line 1) | class CreateCustomFieldCcHandling < ActiveRecord::Migration[5.2]
    method up (line 2) | def self.up
    method down (line 12) | def self.down

FILE: db/migrate/009_create_custom_field_for_reopen_closed_issues_by_email.rb
  class CreateCustomFieldForReopenClosedIssuesByEmail (line 1) | class CreateCustomFieldForReopenClosedIssuesByEmail < ActiveRecord::Migr...
    method up (line 2) | def self.up
    method down (line 12) | def self.down

FILE: db/migrate/010_create_custom_field_for_reply_separator.rb
  class CreateCustomFieldForReplySeparator (line 1) | class CreateCustomFieldForReplySeparator < ActiveRecord::Migration[5.2]
    method up (line 2) | def self.up
    method down (line 17) | def self.down

FILE: lib/helpdesk_hooks.rb
  class HelpdeskHooks (line 1) | class HelpdeskHooks < Redmine::Hook::Listener
    method view_issues_edit_notes_bottom (line 4) | def view_issues_edit_notes_bottom(context={})
    method controller_issues_edit_before_save (line 26) | def controller_issues_edit_before_save(context={})
    method view_issues_history_journal_bottom (line 32) | def view_issues_history_journal_bottom(context={})

FILE: lib/helpdesk_mailer.rb
  class HelpdeskMailer (line 6) | class HelpdeskMailer < ActionMailer::Base
    method default_url_options (line 13) | def self.default_url_options
    method email_to_supportclient (line 18) | def email_to_supportclient(issue, params)
    method redmine_headers (line 115) | def redmine_headers(h)
    method token_for (line 119) | def self.token_for(object, rand=true)
    method message_id_for (line 135) | def self.message_id_for(object)
    method references_for (line 141) | def self.references_for(object)
    method message_id (line 145) | def message_id(object)
    method references (line 149) | def references(object)

FILE: lib/macro_expander.rb
  type MacroExpander (line 1) | module MacroExpander
    function expand_macros (line 2) | def expand_macros(string, issue, journal)
    class Expander (line 7) | class Expander
      method initialize (line 10) | def initialize(string, issue, journal)
      method expand (line 16) | def expand
      method expand_issue (line 29) | def expand_issue
      method expand_project (line 36) | def expand_project
      method expand_user (line 41) | def expand_user
      method expand_user_cf (line 51) | def expand_user_cf(user)
      method expand_base (line 60) | def expand_base

FILE: lib/redmine_helpdesk/journal_patch.rb
  type RedmineHelpdesk (line 1) | module RedmineHelpdesk
    type JournalPatch (line 2) | module JournalPatch
      function included (line 3) | def self.included(base) # :nodoc:
      type InstanceMethods (line 12) | module InstanceMethods
        function send_notification_with_helpdesk (line 15) | def send_notification_with_helpdesk

FILE: lib/redmine_helpdesk/mail_handler_patch.rb
  type RedmineHelpdesk (line 1) | module RedmineHelpdesk
    type MailHandlerPatch (line 2) | module MailHandlerPatch
      function included (line 3) | def self.included(base) # :nodoc:
      type InstanceMethods (line 15) | module InstanceMethods
        function dispatch_to_default_with_helpdesk (line 20) | def dispatch_to_default_with_helpdesk
        function after_dispatch_to_default_hook (line 74) | def after_dispatch_to_default_hook(issue)
        function add_attachments (line 78) | def add_attachments(obj)
        function receive_issue_reply_with_helpdesk (line 93) | def receive_issue_reply_with_helpdesk(issue_id, from_journal=nil)
        function custom_field_value (line 118) | def custom_field_value(issue,name)
        function email_details (line 125) | def email_details

FILE: lib/redmine_helpdesk/mailer_patch.rb
  type RedmineHelpdesk (line 1) | module RedmineHelpdesk
    type MailerPatch (line 2) | module MailerPatch
      function included (line 3) | def self.included(base) # :nodoc:
      type InstanceMethods (line 12) | module InstanceMethods
        function issue_edit_with_helpdesk (line 17) | def issue_edit_with_helpdesk(user, journal)

FILE: lib/tasks/local-db.rake
  function get_env (line 5) | def get_env ()
  function get_port (line 27) | def get_port ()
  function get_image (line 42) | def get_image ()

FILE: test/fixtures/files/2006/07/060719210727_source.rb
  class Greeter (line 2) | class Greeter
    method initialize (line 3) | def initialize(name)
    method salute (line 7) | def salute

FILE: test/functional/issues_controller_with_helpdesk_test.rb
  class IssuesControllerWithHelpdeskTest (line 3) | class IssuesControllerWithHelpdeskTest < ActionController::TestCase
    method setup (line 8) | def setup
    method test_render_send_to_owner_checkbox (line 13) | def test_render_send_to_owner_checkbox

FILE: test/test_helper.rb
  class TestHelper (line 16) | class TestHelper
    method files_path (line 17) | def self.files_path
    method fixture_path (line 20) | def self.fixture_path
  class ActiveSupport::TestCase (line 29) | class ActiveSupport::TestCase

FILE: test/unit/helpdesk_mailer_test.rb
  class HelpdeskMailerTest (line 3) | class HelpdeskMailerTest < ActionMailer::TestCase
    method setup (line 10) | def setup
    method teardown (line 19) | def teardown
    method test_default_url_options (line 23) | def test_default_url_options
    method test_email_headers (line 29) | def test_email_headers
    method test_email_default_sender (line 47) | def test_email_default_sender
    method test_email_helpdesk_sender (line 62) | def test_email_helpdesk_sender
    method test_email_helpdesk_sender_with_phrase (line 71) | def test_email_helpdesk_sender_with_phrase
    method test_first_reply (line 86) | def test_first_reply
    method test_edit (line 99) | def test_edit
    method test_fallback_message_id (line 117) | def test_fallback_message_id
    method test_subject (line 138) | def test_subject
    method test_attachments_added (line 148) | def test_attachments_added

FILE: test/unit/journal_patch_test.rb
  class JournalPatchTest (line 3) | class JournalPatchTest < ActiveSupport::TestCase
    method setup (line 10) | def setup
    method teardown (line 14) | def teardown
    method test_notification_not_sent_when_send_to_owner_false (line 18) | def test_notification_not_sent_when_send_to_owner_false
    method test_notification_not_sent_when_notes_length_zero (line 30) | def test_notification_not_sent_when_notes_length_zero
    method test_notification_note_sent_when_owner_email_blank (line 43) | def test_notification_note_sent_when_owner_email_blank
    method test_notification_sent (line 61) | def test_notification_sent

FILE: test/unit/macro_expander_test.rb
  class MacroExpanderTest (line 3) | class MacroExpanderTest < ActionMailer::TestCase
    method setup (line 10) | def setup
    method teardown (line 19) | def teardown
    method test_expand_issue (line 23) | def test_expand_issue
    method test_expand_project (line 43) | def test_expand_project
    method test_expand_user (line 63) | def test_expand_user
    method test_expand_user_cfs_w_not_existing (line 84) | def test_expand_user_cfs_w_not_existing
    method test_expand_user_no_cfs (line 120) | def test_expand_user_no_cfs
    method test_expand_base (line 142) | def test_expand_base

FILE: test/unit/mail_handler_patch_test.rb
  class MailHandlerPatchTest (line 3) | class MailHandlerPatchTest < ActiveSupport::TestCase
    method setup (line 10) | def setup
    method teardown (line 15) | def teardown
    method test_helpdesk_dispatch_not_supportclient (line 19) | def test_helpdesk_dispatch_not_supportclient
    method test_helpdesk_dispatch_disabled_copy_to (line 35) | def test_helpdesk_dispatch_disabled_copy_to
    method test_helpdesk_dispatch_anonymous_as_supportclient (line 56) | def test_helpdesk_dispatch_anonymous_as_supportclient
    method test_helpdesk_dispatch_anonymous_as_supportclient_with_cc (line 75) | def test_helpdesk_dispatch_anonymous_as_supportclient_with_cc
    method test_helpdesk_dispatch_supportclient (line 102) | def test_helpdesk_dispatch_supportclient
    method submit_email (line 121) | def submit_email(filename, options={})
    method assert_issue_created (line 127) | def assert_issue_created(issue)
Condensed preview — 94 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (144K chars).
[
  {
    "path": ".gitignore",
    "chars": 24,
    "preview": ".DS_Store\n*~\ntest/app/*\n"
  },
  {
    "path": ".travis.yml",
    "chars": 1428,
    "preview": "language: ruby\nrvm:\n- 2.5\n- 2.6\n- jruby\nservices:\n  - mysql\n  - postgresql\nenv:\n  global:\n  - REDMINE_LANG=en\n  - MYSQL_"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 2450,
    "preview": "0.0.20\n---\n* Make plugin compatibility with Redmine 5.0.x\n\n0.0.19\n---\n* Italian translation\n* Fix logger and use new set"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 485,
    "preview": "# Issues\n\nPlease note that I cannot provide user support for this open source project. All issues related to user suppor"
  },
  {
    "path": "Gemfile",
    "chars": 164,
    "preview": "gem \"codeclimate-test-reporter\", group: :test, require: nil\nunless (Gem::Specification::find_all_by_name('rake').any?)\n "
  },
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "Copyright (c) 2012-2021 qutic development GmbH\n\nPermission is hereby granted, free of charge, to any person\nobtaining a "
  },
  {
    "path": "README.md",
    "chars": 10323,
    "preview": "# Redmine Helpdesk\n\nLightweight helpdesk plugin for redmine. Adds the email sender-address of an anonymous supportclient"
  },
  {
    "path": "Rakefile",
    "chars": 48,
    "preview": "Dir.glob('lib/tasks/*.rake').each { |r| load r}\n"
  },
  {
    "path": "app/views/_issue_edit.erb",
    "chars": 130,
    "preview": "<%= check_box_tag('send_to_owner', \"true\", (send_to_owner_default == \"1\")) %> <%=h t('label_support_checkbox') %> (<%=h "
  },
  {
    "path": "app/views/_issue_history.erb",
    "chars": 93,
    "preview": "<i style=\"display:block;margin-bottom:10px;\"><%=h t('email_was_send_to_supportclient') %></i>"
  },
  {
    "path": "config/locales/de.yml",
    "chars": 247,
    "preview": "de:\n  label_support_checkbox: \"E-Mail an Support-Anfragenden senden\"\n  email_was_send_to_supportclient: \"Diese Antwort w"
  },
  {
    "path": "config/locales/en.yml",
    "chars": 139,
    "preview": "en:\n  label_support_checkbox: \"Send mail to supportclient\"\n  email_was_send_to_supportclient: \"This answer was sent to t"
  },
  {
    "path": "config/locales/es.yml",
    "chars": 159,
    "preview": "es:\n  label_support_checkbox: \"Enviar correo al usuario de soporte\"\n  email_was_send_to_supportclient: \"Esta respuesta h"
  },
  {
    "path": "config/locales/it.yml",
    "chars": 136,
    "preview": "it:\n  label_support_checkbox: \"Invia email al cliente\"\n  email_was_send_to_supportclient: \"Questa risposta è stata invia"
  },
  {
    "path": "config/locales/ja.yml",
    "chars": 104,
    "preview": "ja:\n  label_support_checkbox: \"サポート顧客へメールを送信\"\n  email_was_send_to_supportclient: \"この回答はサポート顧客へ送信されました。\"\n"
  },
  {
    "path": "config/locales/pl.yml",
    "chars": 135,
    "preview": "pl:\n  label_support_checkbox: \"Wyślij wiadomość do klienta\"\n  email_was_send_to_supportclient: \"Wiadomość została wysłan"
  },
  {
    "path": "config/locales/ru.yml",
    "chars": 242,
    "preview": "ru:\n  label_support_checkbox: \"Отправить e-mail клиенту поддержки\"\n  email_was_send_to_supportclient: \"Этот ответ был от"
  },
  {
    "path": "config/locales/tr.yml",
    "chars": 180,
    "preview": "tr:\n  label_support_checkbox: \"Bu yanıtı destek isteyen müşteriye e-posta ile gönder\"\n  email_was_send_to_supportclient:"
  },
  {
    "path": "config/locales/zh.yml",
    "chars": 148,
    "preview": "zh:\n  label_support_checkbox: \"发送反馈Email至客户\"\n  email_was_send_to_supportclient: \"反馈邮件已发送至客户。\"\n  permission_treat_user_as"
  },
  {
    "path": "db/migrate/001_create_custom_owner_email_field.rb",
    "chars": 873,
    "preview": "class CreateCustomOwnerEmailField < ActiveRecord::Migration[5.2]\n  def self.up\n    # fix PG:DuplicateColumn errors\n    #"
  },
  {
    "path": "db/migrate/002_create_custom_fields_for_reply.rb",
    "chars": 794,
    "preview": "class CreateCustomFieldsForReply < ActiveRecord::Migration[5.2]\n  def self.up\n    c = CustomField.new(\n      :name => 'h"
  },
  {
    "path": "db/migrate/003_create_custom_field_for_sender_email.rb",
    "chars": 405,
    "preview": "class CreateCustomFieldForSenderEmail < ActiveRecord::Migration[5.2]\n  def self.up\n    c = CustomField.new(\n      :name "
  },
  {
    "path": "db/migrate/004_create_custom_field_for_send_to_owner_default.rb",
    "chars": 484,
    "preview": "class CreateCustomFieldForSendToOwnerDefault < ActiveRecord::Migration[5.2]\n  def self.up\n    c = CustomField.new(\n     "
  },
  {
    "path": "db/migrate/005_add_treat_as_supportclient_to_anonymous.rb",
    "chars": 484,
    "preview": "class AddTreatAsSupportclientToAnonymous < ActiveRecord::Migration[5.2]\n  def self.up\n    anon_id = User.where(type: 'An"
  },
  {
    "path": "db/migrate/006_append_footer_to_first_reply.rb",
    "chars": 870,
    "preview": "class AppendFooterToFirstReply < ActiveRecord::Migration[5.2]\n\n  # Appends helpdesk-email-footer to helpdesk-first-reply"
  },
  {
    "path": "db/migrate/007_create_custom_copy_to_field.rb",
    "chars": 574,
    "preview": "class CreateCustomCopyToField < ActiveRecord::Migration[5.2]\n  def self.up\n    c = CustomField.new(\n      :name => 'copy"
  },
  {
    "path": "db/migrate/008_create_custom_field_cc_handling.rb",
    "chars": 380,
    "preview": "class CreateCustomFieldCcHandling < ActiveRecord::Migration[5.2]\n  def self.up\n    c = CustomField.new(\n      :name => '"
  },
  {
    "path": "db/migrate/009_create_custom_field_for_reopen_closed_issues_by_email.rb",
    "chars": 413,
    "preview": "class CreateCustomFieldForReopenClosedIssuesByEmail < ActiveRecord::Migration[5.2]\n  def self.up\n    c = CustomField.new"
  },
  {
    "path": "db/migrate/010_create_custom_field_for_reply_separator.rb",
    "chars": 605,
    "preview": "class CreateCustomFieldForReplySeparator < ActiveRecord::Migration[5.2]\n  def self.up\n    begin\n      c = CustomField.ne"
  },
  {
    "path": "init.rb",
    "chars": 553,
    "preview": "require 'redmine'\n$LOAD_PATH.unshift \"#{File.dirname(__FILE__)}/lib\"\nrequire 'helpdesk_hooks'\nrequire 'helpdesk_mailer'\n"
  },
  {
    "path": "lib/helpdesk_hooks.rb",
    "chars": 1996,
    "preview": "class HelpdeskHooks < Redmine::Hook::Listener\n  \n  # render partial for 'Send mail to supportclient'\n  def view_issues_e"
  },
  {
    "path": "lib/helpdesk_mailer.rb",
    "chars": 5125,
    "preview": "#\n# With Rails 3 mail is send with the mail method. Sadly redmine\n# uses this method-name too in their mailer. This is t"
  },
  {
    "path": "lib/macro_expander.rb",
    "chars": 1597,
    "preview": "module MacroExpander\n  def expand_macros(string, issue, journal)\n    e = Expander.new(string, issue, journal)\n    e.expa"
  },
  {
    "path": "lib/redmine_helpdesk/journal_patch.rb",
    "chars": 1993,
    "preview": "module RedmineHelpdesk\n  module JournalPatch\n    def self.included(base) # :nodoc:\n      base.send(:include, InstanceMet"
  },
  {
    "path": "lib/redmine_helpdesk/mail_handler_patch.rb",
    "chars": 5363,
    "preview": "module RedmineHelpdesk\n  module MailHandlerPatch\n    def self.included(base) # :nodoc:\n      base.send(:include, Instanc"
  },
  {
    "path": "lib/redmine_helpdesk/mailer_patch.rb",
    "chars": 3496,
    "preview": "module RedmineHelpdesk\n  module MailerPatch\n    def self.included(base) # :nodoc:\n      base.send(:include, InstanceMeth"
  },
  {
    "path": "lib/tasks/local-db.rake",
    "chars": 1712,
    "preview": "namespace :helpdesk do\n  namespace :localdb do\n    db_label = 'helpdesk-db'\n\n    def get_env ()\n      db_name = 'redmine"
  },
  {
    "path": "lib/tasks/plugin_ci.rake",
    "chars": 1738,
    "preview": "namespace :helpdesk do\n  plugin_root = File.expand_path('../../../', __FILE__)\n  coverage_dir = \"#{plugin_root}/coverage"
  },
  {
    "path": "lib/tasks/redmine.rake",
    "chars": 2890,
    "preview": "require 'fileutils'\n\nnamespace :helpdesk do\n  namespace :redmine do\n    plugin_root = File.expand_path('../../../', __FI"
  },
  {
    "path": "test/confs/database_mysql.yml",
    "chars": 1030,
    "preview": "## MySQL configuration example\n## Data come from environment variables so the test suite can be run\n## on Travis or Jenk"
  },
  {
    "path": "test/confs/database_postgres.yml",
    "chars": 672,
    "preview": "## PostgreSQL configuration example\n## Data come from environment variables so the test suite can be run\n## on Travis or"
  },
  {
    "path": "test/confs/database_postgres_ext.yml",
    "chars": 825,
    "preview": "## PostgreSQL configuration example\n## Data come from environment variables so the test suite can be run\n## on Travis or"
  },
  {
    "path": "test/confs/database_sqlite.yml",
    "chars": 223,
    "preview": "## SQLite3 configuration example\nproduction:\n  adapter: sqlite3\n  database: db/redmine.sqlite3\ndevelopment:\n  adapter: s"
  },
  {
    "path": "test/fixtures/2.6/attachments.yml",
    "chars": 368,
    "preview": "---\nattachments_001:\n  created_on: 2006-07-19 21:07:27 +02:00\n  container_type: Issue\n  container_id: 1\n  downloads: 0\n "
  },
  {
    "path": "test/fixtures/2.6/custom_fields.yml",
    "chars": 2515,
    "preview": "---\ncustom_fields_001:\n  name: owner-email\n  regexp: \"\"\n  type: IssueCustomField\n  possible_values: \"\"\n  id: 1\n  is_requ"
  },
  {
    "path": "test/fixtures/2.6/custom_fields_projects.yml",
    "chars": 397,
    "preview": "---\ncustom_fields_projects_001:\n  custom_field_id: 1\n  project_id: 1\ncustom_fields_projects_002:\n  custom_field_id: 1\n  "
  },
  {
    "path": "test/fixtures/2.6/custom_fields_trackers.yml",
    "chars": 528,
    "preview": "---\ncustom_fields_trackers_001:\n  custom_field_id: 1\n  tracker_id: 1\ncustom_fields_trackers_002:\n  custom_field_id: 1\n  "
  },
  {
    "path": "test/fixtures/2.6/custom_values.yml",
    "chars": 1823,
    "preview": "---\ncustom_values_001:\n  customized_type: Project\n  custom_field_id: 2\n  customized_id: 1\n  id: 1\n  value: \"first reply\""
  },
  {
    "path": "test/fixtures/2.6/enabled_modules.yml",
    "chars": 586,
    "preview": "---\nenabled_modules_001:\n  name: issue_tracking\n  project_id: 1\n  id: 1\nenabled_modules_002:\n  name: time_tracking\n  pro"
  },
  {
    "path": "test/fixtures/2.6/enumerations.yml",
    "chars": 601,
    "preview": "---\nenumerations_001:\n  name: Low\n  id: 1\n  type: IssuePriority\n  active: true\n  position: 1\n  position_name: lowest\nenu"
  },
  {
    "path": "test/fixtures/2.6/issue_statuses.yml",
    "chars": 589,
    "preview": "--- \nissue_statuses_001: \n  id: 1\n  name: New\n  is_default: true\n  is_closed: false\n  position: 1\nissue_statuses_002: \n "
  },
  {
    "path": "test/fixtures/2.6/issues.yml",
    "chars": 810,
    "preview": "---\nissues_001:\n  created_on: 2015-03-05 21:41:21 +02:00\n  project_id: 1\n  updated_on: 2015-03-05 22:05:50 +02:00\n  prio"
  },
  {
    "path": "test/fixtures/2.6/journal_details.yml",
    "chars": 131,
    "preview": "---\njournal_details_001:\n  old_value:\n  property: attachment\n  id: 1\n  value: 060719210727_source.rb\n  prop_key: 1\n  jou"
  },
  {
    "path": "test/fixtures/2.6/journals.yml",
    "chars": 652,
    "preview": "---\njournals_001:\n  created_on: <%= 2.days.ago.to_date.to_s(:db) %>\n  notes: \"Journal notes\"\n  id: 1\n  journalized_type:"
  },
  {
    "path": "test/fixtures/2.6/member_roles.yml",
    "chars": 220,
    "preview": "---\nmember_roles_001:\n  id: 1\n  role_id: 1\n  member_id: 1\nmember_roles_002:\n  id: 2\n  role_id: 1\n  member_id: 2\nmember_r"
  },
  {
    "path": "test/fixtures/2.6/members.yml",
    "chars": 590,
    "preview": "---\nmembers_001:\n  created_on: 2006-07-19 19:35:33 +02:00\n  project_id: 1\n  id: 1\n  user_id: 1\n  mail_notification: true"
  },
  {
    "path": "test/fixtures/2.6/projects.yml",
    "chars": 1097,
    "preview": "---\nprojects_001:\n  created_on: 2015-03-05 19:13:59 +02:00\n  name: Helpdesk Project 1\n  updated_on: 2015-03-05 22:53:01 "
  },
  {
    "path": "test/fixtures/2.6/projects_trackers.yml",
    "chars": 664,
    "preview": "---\nprojects_trackers_001:\n  project_id: 1\n  tracker_id: 1\nprojects_trackers_002:\n  project_id: 1\n  tracker_id: 2\nprojec"
  },
  {
    "path": "test/fixtures/2.6/roles.yml",
    "chars": 4296,
    "preview": "---\nroles_001:\n  name: Manager\n  id: 1\n  builtin: 0\n  issues_visibility: all\n  permissions: |\n    ---\n    - :add_project"
  },
  {
    "path": "test/fixtures/2.6/trackers.yml",
    "chars": 237,
    "preview": "--- \ntrackers_001: \n  name: Bug\n  id: 1\n  is_in_chlog: true\n  position: 1\ntrackers_002: \n  name: Feature request\n  id: 2"
  },
  {
    "path": "test/fixtures/2.6/users.yml",
    "chars": 1153,
    "preview": "---\nusers_001:\n  created_on: 2015-03-05 19:34:07 +02:00\n  status: 1\n  last_login_on:\n  language: en\n  # password = foo\n "
  },
  {
    "path": "test/fixtures/3.0/attachments.yml",
    "chars": 368,
    "preview": "---\nattachments_001:\n  created_on: 2006-07-19 21:07:27 +02:00\n  container_type: Issue\n  container_id: 1\n  downloads: 0\n "
  },
  {
    "path": "test/fixtures/3.0/custom_fields.yml",
    "chars": 2515,
    "preview": "---\ncustom_fields_001:\n  name: owner-email\n  regexp: \"\"\n  type: IssueCustomField\n  possible_values: \"\"\n  id: 1\n  is_requ"
  },
  {
    "path": "test/fixtures/3.0/custom_fields_projects.yml",
    "chars": 397,
    "preview": "---\ncustom_fields_projects_001:\n  custom_field_id: 1\n  project_id: 1\ncustom_fields_projects_002:\n  custom_field_id: 1\n  "
  },
  {
    "path": "test/fixtures/3.0/custom_fields_trackers.yml",
    "chars": 528,
    "preview": "---\ncustom_fields_trackers_001:\n  custom_field_id: 1\n  tracker_id: 1\ncustom_fields_trackers_002:\n  custom_field_id: 1\n  "
  },
  {
    "path": "test/fixtures/3.0/custom_values.yml",
    "chars": 1823,
    "preview": "---\ncustom_values_001:\n  customized_type: Project\n  custom_field_id: 2\n  customized_id: 1\n  id: 1\n  value: \"first reply\""
  },
  {
    "path": "test/fixtures/3.0/email_addresses.yml",
    "chars": 346,
    "preview": "---\nemail_address_001:\n  id: 1\n  user_id: 1\n  address: rhill@somenet.foo\n  is_default: true\n  created_on: 2006-07-19 19:"
  },
  {
    "path": "test/fixtures/3.0/enabled_modules.yml",
    "chars": 586,
    "preview": "---\nenabled_modules_001:\n  name: issue_tracking\n  project_id: 1\n  id: 1\nenabled_modules_002:\n  name: time_tracking\n  pro"
  },
  {
    "path": "test/fixtures/3.0/enumerations.yml",
    "chars": 601,
    "preview": "---\nenumerations_001:\n  name: Low\n  id: 1\n  type: IssuePriority\n  active: true\n  position: 1\n  position_name: lowest\nenu"
  },
  {
    "path": "test/fixtures/3.0/issue_statuses.yml",
    "chars": 463,
    "preview": "---\nissue_statuses_001:\n  id: 1\n  name: New\n  is_closed: false\n  position: 1\nissue_statuses_002:\n  id: 2\n  name: Assigne"
  },
  {
    "path": "test/fixtures/3.0/issues.yml",
    "chars": 810,
    "preview": "---\nissues_001:\n  created_on: 2015-03-05 21:41:21 +02:00\n  project_id: 1\n  updated_on: 2015-03-05 22:05:50 +02:00\n  prio"
  },
  {
    "path": "test/fixtures/3.0/journal_details.yml",
    "chars": 131,
    "preview": "---\njournal_details_001:\n  old_value:\n  property: attachment\n  id: 1\n  value: 060719210727_source.rb\n  prop_key: 1\n  jou"
  },
  {
    "path": "test/fixtures/3.0/journals.yml",
    "chars": 652,
    "preview": "---\njournals_001:\n  created_on: <%= 2.days.ago.to_date.to_s(:db) %>\n  notes: \"Journal notes\"\n  id: 1\n  journalized_type:"
  },
  {
    "path": "test/fixtures/3.0/member_roles.yml",
    "chars": 220,
    "preview": "---\nmember_roles_001:\n  id: 1\n  role_id: 1\n  member_id: 1\nmember_roles_002:\n  id: 2\n  role_id: 1\n  member_id: 2\nmember_r"
  },
  {
    "path": "test/fixtures/3.0/members.yml",
    "chars": 590,
    "preview": "---\nmembers_001:\n  created_on: 2006-07-19 19:35:33 +02:00\n  project_id: 1\n  id: 1\n  user_id: 1\n  mail_notification: true"
  },
  {
    "path": "test/fixtures/3.0/projects.yml",
    "chars": 1097,
    "preview": "---\nprojects_001:\n  created_on: 2015-03-05 19:13:59 +02:00\n  name: Helpdesk Project 1\n  updated_on: 2015-03-05 22:53:01 "
  },
  {
    "path": "test/fixtures/3.0/projects_trackers.yml",
    "chars": 664,
    "preview": "---\nprojects_trackers_001:\n  project_id: 1\n  tracker_id: 1\nprojects_trackers_002:\n  project_id: 1\n  tracker_id: 2\nprojec"
  },
  {
    "path": "test/fixtures/3.0/roles.yml",
    "chars": 4296,
    "preview": "---\nroles_001:\n  name: Manager\n  id: 1\n  builtin: 0\n  issues_visibility: all\n  permissions: |\n    ---\n    - :add_project"
  },
  {
    "path": "test/fixtures/3.0/trackers.yml",
    "chars": 302,
    "preview": "---\ntrackers_001:\n  name: Bug\n  id: 1\n  is_in_chlog: true\n  position: 1\n  default_status_id: 1\ntrackers_002:\n  name: Fea"
  },
  {
    "path": "test/fixtures/3.0/users.yml",
    "chars": 1099,
    "preview": "---\nusers_001:\n  created_on: 2015-03-05 19:34:07 +02:00\n  status: 1\n  last_login_on:\n  language: en\n  # password = foo\n "
  },
  {
    "path": "test/fixtures/files/2006/07/060719210727_source.rb",
    "chars": 143,
    "preview": "# The Greeter class\nclass Greeter\n  def initialize(name)\n    @name = name.capitalize\n  end\n\n  def salute\n    puts \"Hello"
  },
  {
    "path": "test/fixtures/mail_handler/ticket_by_unknown_user.eml",
    "chars": 508,
    "preview": "Return-Path: <john.doe@somenet.foo>\nReceived: from osiris ([127.0.0.1])\n\tby OSIRIS\n\twith hMailServer ; Sun, 22 Jun 2008 "
  },
  {
    "path": "test/fixtures/mail_handler/ticket_by_unknown_user_with_cc.eml",
    "chars": 617,
    "preview": "Return-Path: <john.doe@somenet.foo>\nReceived: from osiris ([127.0.0.1])\n\tby OSIRIS\n\twith hMailServer ; Sun, 22 Jun 2008 "
  },
  {
    "path": "test/fixtures/mail_handler/ticket_by_user_1.eml",
    "chars": 502,
    "preview": "Return-Path: <rhill@somenet.foo>\nReceived: from osiris ([127.0.0.1])\n\tby OSIRIS\n\twith hMailServer ; Sun, 22 Jun 2008 12:"
  },
  {
    "path": "test/fixtures/mail_handler/ticket_by_user_2.eml",
    "chars": 506,
    "preview": "Return-Path: <dlopper@somenet.foo>\nReceived: from osiris ([127.0.0.1])\n\tby OSIRIS\n\twith hMailServer ; Sun, 22 Jun 2008 1"
  },
  {
    "path": "test/fixtures/mail_handler/ticket_reply.eml",
    "chars": 1938,
    "preview": "Return-Path: <jsmith@somenet.foo>\nReceived: from osiris ([127.0.0.1])\n\tby OSIRIS\n\twith hMailServer ; Sat, 21 Jun 2008 18"
  },
  {
    "path": "test/fixtures/mail_handler/ticket_with_attachment.eml",
    "chars": 16308,
    "preview": "Return-Path: <jsmith@somenet.foo>\nReceived: from osiris ([127.0.0.1])\n\tby OSIRIS\n\twith hMailServer ; Sat, 21 Jun 2008 15"
  },
  {
    "path": "test/fixtures/mail_handler/ticket_with_attributes.eml",
    "chars": 1901,
    "preview": "Return-Path: <jsmith@somenet.foo>\nReceived: from osiris ([127.0.0.1])\n\tby OSIRIS\n\twith hMailServer ; Sun, 22 Jun 2008 12"
  },
  {
    "path": "test/functional/issues_controller_with_helpdesk_test.rb",
    "chars": 4050,
    "preview": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass IssuesControllerWithHelpdeskTest < ActionController::TestCase\n"
  },
  {
    "path": "test/test_helper.rb",
    "chars": 794,
    "preview": "require \"simplecov\"\nrequire \"codeclimate-test-reporter\"\n\nSimpleCov.use_merging true\nSimpleCov.merge_timeout 3600\nSimpleC"
  },
  {
    "path": "test/unit/helpdesk_mailer_test.rb",
    "chars": 5866,
    "preview": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass HelpdeskMailerTest < ActionMailer::TestCase\n  include Redmine:"
  },
  {
    "path": "test/unit/journal_patch_test.rb",
    "chars": 2054,
    "preview": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass JournalPatchTest < ActiveSupport::TestCase\n  include Redmine::"
  },
  {
    "path": "test/unit/macro_expander_test.rb",
    "chars": 5278,
    "preview": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass MacroExpanderTest < ActionMailer::TestCase\n  include Redmine::"
  },
  {
    "path": "test/unit/mail_handler_patch_test.rb",
    "chars": 5081,
    "preview": "require File.dirname(__FILE__) + '/../test_helper'\n\nclass MailHandlerPatchTest < ActiveSupport::TestCase\n  include Redmi"
  }
]

About this extraction

This page contains the full source code of the jfqd/redmine_helpdesk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 94 files (130.0 KB), approximately 46.8k tokens, and a symbol index with 124 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!