with long strings may hang server
-* Defect #7337: My page french translation
-* Defect #7348: French Translation of "Connection"
-* Defect #7385: Error when viewing an issue which was related to a deleted subtask
-* Defect #7386: NoMethodError on pdf export
-* Defect #7415: Darcs adapter recognizes new files as modified files above Darcs 2.4
-* Defect #7421: no email sent with 'Notifiy for any event on the selected projects only'
-* Feature #5344: Update to latest CodeRay 0.9.x
-
-== 2011-01-09 v1.1.0
-
-* Defect #2038: Italics in wiki headers show-up wrong in the toc
-* Defect #3449: Redmine Takes Too Long On Large Mercurial Repository
-* Defect #3567: Sorting for changesets might go wrong on Mercurial repos
-* Defect #3707: {{toc}} doesn't work with {{include}}
-* Defect #5096: Redmine hangs up while browsing Git repository
-* Defect #6000: Safe Attributes prevents plugin extension of Issue model...
-* Defect #6064: Modules not assigned to projects created via API
-* Defect #6110: MailHandler should allow updating Issue Priority and Custom fields
-* Defect #6136: JSON API holds less information than XML API
-* Defect #6345: xml used by rest API is invalid
-* Defect #6348: Gantt chart PDF rendering errors
-* Defect #6403: Updating an issue with custom fields fails
-* Defect #6467: "Member of role", "Member of group" filter not work correctly
-* Defect #6473: New gantt broken after clearing issue filters
-* Defect #6541: Email notifications send to everybody
-* Defect #6549: Notification settings not migrated properly
-* Defect #6591: Acronyms must have a minimum of three characters
-* Defect #6674: Delete time log broken after changes to REST
-* Defect #6681: Mercurial, Bazaar and Darcs auto close issue text should be commit id instead of revision number
-* Defect #6724: Wiki uploads does not work anymore (SVN 4266)
-* Defect #6746: Wiki links are broken on Activity page
-* Defect #6747: Wiki diff does not work since r4265
-* Defect #6763: New gantt charts: subject displayed twice on issues
-* Defect #6826: Clicking "Add" twice creates duplicate member record
-* Defect #6844: Unchecking status filter on the issue list has no effect
-* Defect #6895: Wrong Polish translation of "blocks"
-* Defect #6943: Migration from boolean to varchar fails on PostgreSQL 8.1
-* Defect #7064: Mercurial adapter does not recognize non alphabetic nor numeric in UTF-8 copied files
-* Defect #7128: New gantt chart does not render subtasks under parent task
-* Defect #7135: paging mechanism returns the same last page forever
-* Defect #7188: Activity page not refreshed when changing language
-* Defect #7195: Apply CLI-supplied defaults for incoming mail only to new issues not replies
-* Defect #7197: Tracker reset to default when replying to an issue email
-* Defect #7213: Copy project does not copy all roles and permissions
-* Defect #7225: Project settings: Trackers & Custom fields only relevant if module Issue tracking is active
-* Feature #630: Allow non-unique names for projects
-* Feature #1738: Add a "Visible" flag to project/user custom fields
-* Feature #2803: Support for Javascript in Themes
-* Feature #2852: Clean Incoming Email of quoted text "----- Reply above this line ------"
-* Feature #2995: Improve error message when trying to access an archived project
-* Feature #3170: Autocomplete issue relations on subject
-* Feature #3503: Administrator Be Able To Modify Email settings Of Users
-* Feature #4155: Automatic spent time logging from commit messages
-* Feature #5136: Parent select on Wiki rename page
-* Feature #5338: Descendants (subtasks) should be available via REST API
-* Feature #5494: Wiki TOC should display heading from level 4
-* Feature #5594: Improve MailHandler's keyword handling
-* Feature #5622: Allow version to be set via incoming email
-* Feature #5712: Reload themes
-* Feature #5869: Issue filters by Group and Role
-* Feature #6092: Truncate Git revision labels in Activity page/feed and allow configurable length
-* Feature #6112: Accept localized keywords when receiving emails
-* Feature #6140: REST issues response with issue count limit and offset
-* Feature #6260: REST API for Users
-* Feature #6276: Gantt Chart rewrite
-* Feature #6446: Remove length limits on project identifier and name
-* Feature #6628: Improvements in truncate email
-* Feature #6779: Project JSON API
-* Feature #6823: REST API for time tracker.
-* Feature #7072: REST API for news
-* Feature #7111: Expose more detail on journal entries
-* Feature #7141: REST API: get information about current user
-* Patch #4807: Allow to set the done_ratio field with the incoming mail system
-* Patch #5441: Initialize TimeEntry attributes with params[:time_entry]
-* Patch #6762: Use GET instead of POST to retrieve context_menu
-* Patch #7160: French translation ofr "not_a_date" is missing
-* Patch #7212: Missing remove_index in AddUniqueIndexOnMembers down migration
-
-
-== 2010-12-23 v1.0.5
-
-* #6656: Mercurial adapter loses seconds of commit times
-* #6996: Migration trac(sqlite3) -> redmine(postgresql) doesnt escape ' char
-* #7013: v-1.0.4 trunk - see {{count}} in page display rather than value
-* #7016: redundant 'field_start_date' in ja.yml
-* #7018: 'undefined method `reschedule_after' for nil:NilClass' on new issues
-* #7024: E-mail notifications about Wiki changes.
-* #7033: 'class' attribute of tag shouldn't be truncate
-* #7035: CSV value separator in russian
-* #7122: Issue-description Quote-button missing
-* #7144: custom queries making use of deleted custom fields cause a 500 error
-* #7162: Multiply defined label in french translation
-
-== 2010-11-28 v1.0.4
-
-* #5324: Git not working if color.ui is enabled
-* #6447: Issues API doesn't allow full key auth for all actions
-* #6457: Edit User group problem
-* #6575: start date being filled with current date even when blank value is submitted
-* #6740: Max attachment size, incorrect usage of 'KB'
-* #6760: Select box sorted by ID instead of name in Issue Category
-* #6766: Changing target version name can cause an internal error
-* #6784: Redmine not working with i18n gem 0.4.2
-* #6839: Hardcoded absolute links in my/page_layout
-* #6841: Projects API doesn't allow full key auth for all actions
-* #6860: svn: Write error: Broken pipe when browsing repository
-* #6874: API should return XML description when creating a project
-* #6932: submitting wrong parent task input creates a 500 error
-* #6966: Records of Forums are remained, deleting project
-* #6990: Layout problem in workflow overview
-* #5117: mercurial_adapter should ensure the right LANG environment variable
-* #6782: Traditional Chinese language file (to r4352)
-* #6783: Swedish Translation for r4352
-* #6804: Bugfix: spelling fixes
-* #6814: Japanese Translation for r4362
-* #6948: Bulgarian translation
-* #6973: Update es.yml
-
-== 2010-10-31 v1.0.3
-
-* #4065: Redmine.pm doesn't work with LDAPS and a non-standard port
-* #4416: Link from version details page to edit the wiki.
-* #5484: Add new issue as subtask to an existing ticket
-* #5948: Update help/wiki_syntax_detailed.html with more link options
-* #6494: Typo in pt_BR translation for 1.0.2
-* #6508: Japanese translation update
-* #6509: Localization pt-PT (new strings)
-* #6511: Rake task to test email
-* #6525: Traditional Chinese language file (to r4225)
-* #6536: Patch for swedish translation
-* #6548: Rake tasks to add/remove i18n strings
-* #6569: Updated Hebrew translation
-* #6570: Japanese Translation for r4231
-* #6596: pt-BR translation updates
-* #6629: Change field-name of issues start date
-* #6669: Bulgarian translation
-* #6731: Macedonian translation fix
-* #6732: Japanese Translation for r4287
-* #6735: Add user-agent to reposman
-* #6736: Traditional Chinese language file (to r4288)
-* #6739: Swedish Translation for r4288
-* #6765: Traditional Chinese language file (to r4302)
-* Fixed #5324: Git not working if color.ui is enabled
-* Fixed #5652: Bad URL parsing in the wiki when it ends with right-angle-bracket(greater-than mark).
-* Fixed #5803: Precedes/Follows Relationships Broke
-* Fixed #6435: Links to wikipages bound to versions do not respect version-sharing in Settings -> Versions
-* Fixed #6438: Autologin cannot be disabled again once it's enabled
-* Fixed #6513: "Move" and "Copy" are not displayed when deployed in subdirectory
-* Fixed #6521: Tooltip/label for user "search-refinment" field on group/project member list
-* Fixed #6563: i18n-issues on calendar view
-* Fixed #6598: Wrong caption for button_create_and_continue in German language file
-* Fixed #6607: Unclear caption for german button_update
-* Fixed #6612: SortHelper missing from CalendarsController
-* Fixed #6740: Max attachment size, incorrect usage of 'KB'
-* Fixed #6750: ActionView::TemplateError (undefined method `empty?' for nil:NilClass) on line #12 of app/views/context_menus/issues.html.erb:
-
-== 2010-09-26 v1.0.2
-
-* #2285: issue-refinement: pressing enter should result to an "apply"
-* #3411: Allow mass status update trough context menu
-* #5929: https-enabled gravatars when called over https
-* #6189: Japanese Translation for r4011
-* #6197: Traditional Chinese language file (to r4036)
-* #6198: Updated german translation
-* #6208: Macedonian translation
-* #6210: Swedish Translation for r4039
-* #6248: nl translation update for r4050
-* #6263: Catalan translation update
-* #6275: After submitting a related issue, the Issue field should be re-focused
-* #6289: Checkboxes in issues list shouldn't be displayed when printing
-* #6290: Make journals theming easier
-* #6291: User#allowed_to? is not tested
-* #6306: Traditional Chinese language file (to r4061)
-* #6307: Korean translation update for 4066(4061)
-* #6316: pt_BR update
-* #6339: SERBIAN Updated
-* #6358: Updated Polish translation
-* #6363: Japanese Translation for r4080
-* #6365: Traditional Chinese language file (to r4081)
-* #6382: Issue PDF export variable usage
-* #6428: Interim solution for i18n >= 0.4
-* #6441: Japanese Translation for r4162
-* #6451: Traditional Chinese language file (to r4167)
-* #6465: Japanese Translation for r4171
-* #6466: Traditional Chinese language file (to r4171)
-* #6490: pt-BR translation for 1.0.2
-* Fixed #3935: stylesheet_link_tag with plugin doesn't take into account relative_url_root
-* Fixed #4998: Global issue list's context menu has enabled options for parent menus but there are no valid selections
-* Fixed #5170: Done ratio can not revert to 0% if status is used for done ratio
-* Fixed #5608: broken with i18n 0.4.0
-* Fixed #6054: Error 500 on filenames with whitespace in git reposities
-* Fixed #6135: Default logger configuration grows without bound.
-* Fixed #6191: Deletion of a main task deletes all subtasks
-* Fixed #6195: Missing move issues between projects
-* Fixed #6242: can't switch between inline and side-by-side diff
-* Fixed #6249: Create and continue returns 404
-* Fixed #6267: changing the authentication mode from ldap to internal with setting the password
-* Fixed #6270: diff coderay malformed in the "news" page
-* Fixed #6278: missing "cant_link_an_issue_with_a_descendant"from locale files
-* Fixed #6333: Create and continue results in a 404 Error
-* Fixed #6346: Age column on repository view is skewed for git, probably CVS too
-* Fixed #6351: Context menu on roadmap broken
-* Fixed #6388: New Subproject leads to a 404
-* Fixed #6392: Updated/Created links to activity broken
-* Fixed #6413: Error in SQL
-* Fixed #6443: Redirect to project settings after Copying a Project
-* Fixed #6448: Saving a wiki page with no content has a translation missing
-* Fixed #6452: Unhandled exception on creating File
-* Fixed #6471: Typo in label_report in Czech translation
-* Fixed #6479: Changing tracker type will lose watchers
-* Fixed #6499: Files with leading or trailing whitespace are not shown in git.
-
-== 2010-08-22 v1.0.1
-
-* #819: Add a body ID and class to all pages
-* #871: Commit new CSS styles!
-* #3301: Add favicon to base layout
-* #4656: On Issue#show page, clicking on “Add related issue� should focus on the input
-* #4896: Project identifier should be a limited field
-* #5084: Filter all isssues by projects
-* #5477: Replace Test::Unit::TestCase with ActiveSupport::TestCase
-* #5591: 'calendar' action is used with 'issue' controller in issue/sidebar
-* #5735: Traditional Chinese language file (to r3810)
-* #5740: Swedish Translation for r3810
-* #5785: pt-BR translation update
-* #5898: Projects should be displayed as links in users/memberships
-* #5910: Chinese translation to redmine-1.0.0
-* #5912: Translation update for french locale
-* #5962: Hungarian translation update to r3892
-* #5971: Remove falsly applied chrome on revision links
-* #5972: Updated Hebrew translation for 1.0.0
-* #5982: Updated german translation
-* #6008: Move admin_menu to Redmine::MenuManager
-* #6012: RTL layout
-* #6021: Spanish translation 1.0.0-RC
-* #6025: nl translation updated for r3905
-* #6030: Japanese Translation for r3907
-* #6074: sr-CY.yml contains DOS-type newlines (\r\n)
-* #6087: SERBIAN translation updated
-* #6093: Updated italian translation
-* #6142: Swedish Translation for r3940
-* #6153: Move view_calendar and view_gantt to own modules
-* #6169: Add issue status to issue tooltip
-* Fixed #3834: Add a warning when not choosing a member role
-* Fixed #3922: Bad english arround "Assigned to" text in journal entries
-* Fixed #5158: Simplified Chinese language file zh.yml updated to r3608
-* Fixed #5162: translation missing: zh-TW, field_time_entrie
-* Fixed #5297: openid not validated correctly
-* Fixed #5628: Wrong commit range in git log command
-* Fixed #5760: Assigned_to and author filters in "Projects>View all issues" should be based on user's project visibility
-* Fixed #5771: Problem when importing git repository
-* Fixed #5775: ldap authentication in admin menu should have an icon
-* Fixed #5811: deleting statuses doesnt delete workflow entries
-* Fixed #5834: Emails with trailing spaces incorrectly detected as invalid
-* Fixed #5846: ChangeChangesPathLengthLimit does not remove default for MySQL
-* Fixed #5861: Vertical scrollbar always visible in Wiki "code" blocks in Chrome.
-* Fixed #5883: correct label_project_latest Chinese translation
-* Fixed #5892: Changing status from contextual menu opens the ticket instead
-* Fixed #5904: Global gantt PDF and PNG should display project names
-* Fixed #5925: parent task's priority edit should be disabled through shortcut menu in issues list page
-* Fixed #5935: Add Another file to ticket doesn't work in IE Internet Explorer
-* Fixed #5937: Harmonize french locale "zero" translation with other locales
-* Fixed #5945: Forum message permalinks don't take pagination into account
-* Fixed #5978: Debug code still remains
-* Fixed #6009: When using "English (British)", the repository browser (svn) shows files over 1000 bytes as floating point (2.334355)
-* Fixed #6045: Repository file Diff view sometimes shows more than selected file
-* Fixed #6079: German Translation error in TimeEntryActivity
-* Fixed #6100: User's profile should display all visible projects
-* Fixed #6132: Allow Key based authentication in the Boards atom feed
-* Fixed #6163: Bad CSS class for calendar project menu_item
-* Fixed #6172: Browsing to a missing user's page shows the admin sidebar
-
-== 2010-07-18 v1.0.0 (Release candidate)
-
-* #443: Adds context menu to the roadmap issue lists
-* #443: Subtasking
-* #741: Description preview while editing an issue
-* #1131: Add support for alternate (non-LDAP) authentication
-* #1214: REST API for Issues
-* #1223: File upload on wiki edit form
-* #1755: add "blocked by" as a related issues option
-* #2420: Fetching emails from an POP server
-* #2482: Named scopes in Issue and ActsAsWatchable plus some view refactoring (logic extraction).
-* #2924: Make the right click menu more discoverable using a cursor property
-* #2985: Make syntax highlighting pluggable
-* #3201: Workflow Check/Uncheck All Rows/Columns
-* #3359: Update CodeRay 0.9
-* #3706: Allow assigned_to field configuration on Issue creation by email
-* #3936: configurable list of models to include in search
-* #4480: Create a link to the user profile from the administration interface
-* #4482: Cache textile rendering
-* #4572: Make it harder to ruin your database
-* #4573: Move github gems to Gemcutter
-* #4664: Add pagination to forum threads
-* #4732: Make login case-insensitive also for PostgreSQL
-* #4812: Create links to other projects
-* #4819: Replace images with smushed ones for speed
-* #4945: Allow custom fields attached to project to be searchable
-* #5121: Fix issues list layout overflow
-* #5169: Issue list view hook request
-* #5208: Aibility to edit wiki sidebar
-* #5281: Remove empty ul tags in the issue history
-* #5291: Updated basque translations
-* #5328: Automatically add "Repository" menu_item after repository creation
-* #5415: Fewer SQL statements generated for watcher_recipients
-* #5416: Exclude "fields_for" from overridden methods in TabularFormBuilder
-* #5573: Allow issue assignment in email
-* #5595: Allow start date and due dates to be set via incoming email
-* #5752: The projects view (/projects) renders ul's wrong
-* #5781: Allow to use more macros on the welcome page and project list
-* Fixed #1288: Unable to past escaped wiki syntax in an issue description
-* Fixed #1334: Wiki formatting character *_ and _*
-* Fixed #1416: Inline code with less-then/greater-than produces @lt; and @gt; respectively
-* Fixed #2473: Login and mail should not be case sensitive
-* Fixed #2990: Ruby 1.9 - wrong number of arguments (1 for 0) on rake db:migrate
-* Fixed #3089: Text formatting sometimes breaks when combined
-* Fixed #3690: Status change info duplicates on the issue screen
-* Fixed #3691: Redmine allows two files with the same file name to be uploaded to the same issue
-* Fixed #3764: ApplicationHelperTest fails with JRuby
-* Fixed #4265: Unclosed code tags in issue descriptions affects main UI
-* Fixed #4745: Bug in index.xml.builder (issues)
-* Fixed #4852: changing user/roles of project member not possible without javascript
-* Fixed #4857: Week number calculation in date picker is wrong if a week starts with Sunday
-* Fixed #4883: Bottom "contextual" placement in issue with associated changeset
-* Fixed #4918: Revisions r3453 and r3454 broke On-the-fly user creation with LDAP
-* Fixed #4935: Navigation to the Master Timesheet page (time_entries)
-* Fixed #5043: Flash messages are not displayed after the project settings[module/activity] saved
-* Fixed #5081: Broken links on public/help/wiki_syntax_detailed.html
-* Fixed #5104: Description of document not wikified on documents index
-* Fixed #5108: Issue linking fails inside of []s
-* Fixed #5199: diff code coloring using coderay
-* Fixed #5233: Add a hook to the issue report (Summary) view
-* Fixed #5265: timetracking: subtasks time is added to the main task
-* Fixed #5343: acts_as_event Doesn't Accept Outside URLs
-* Fixed #5440: UI Inconsistency : Administration > Enumerations table row headers should be enclosed in
-* Fixed #5463: 0.9.4 INSTALL and/or UPGRADE, missing session_store.rb
-* Fixed #5524: Update_parent_attributes doesn't work for the old parent issue when reparenting
-* Fixed #5548: SVN Repository: Can not list content of a folder which includes square brackets.
-* Fixed #5589: "with subproject" malfunction
-* Fixed #5676: Search for Numeric Value
-* Fixed #5696: Redmine + PostgreSQL 8.4.4 fails on _dir_list_content.rhtml
-* Fixed #5698: redmine:email:receive_imap fails silently for mails with subject longer than 255 characters
-* Fixed #5700: TimelogController#destroy assumes success
-* Fixed #5751: developer role is mispelled
-* Fixed #5769: Popup Calendar doesn't Advance in Chrome
-* Fixed #5771: Problem when importing git repository
-* Fixed #5823: Error in comments in plugin.rb
-
-
-== 2010-07-07 v0.9.6
-
-* Fixed: Redmine.pm access by unauthorized users
-
-== 2010-06-24 v0.9.5
-
-* Linkify folder names on revision view
-* "fiters" and "options" should be hidden in print view via css
-* Fixed: NoMethodError when no issue params are submitted
-* Fixed: projects.atom with required authentication
-* Fixed: External links not correctly displayed in Wiki TOC
-* Fixed: Member role forms in project settings are not hidden after member added
-* Fixed: pre can't be inside p
-* Fixed: session cookie path does not respect RAILS_RELATIVE_URL_ROOT
-* Fixed: mail handler fails when the from address is empty
-
-
-== 2010-05-01 v0.9.4
-
-* Filters collapsed by default on issues index page for a saved query
-* Fixed: When categories list is too big the popup menu doesn't adjust (ex. in the issue list)
-* Fixed: remove "main-menu" div when the menu is empty
-* Fixed: Code syntax highlighting not working in Document page
-* Fixed: Git blame/annotate fails on moved files
-* Fixed: Failing test in test_show_atom
-* Fixed: Migrate from trac - not displayed Wikis
-* Fixed: Email notifications on file upload sent to empty recipient list
-* Fixed: Migrating from trac is not possible, fails to allocate memory
-* Fixed: Lost password no longer flashes a confirmation message
-* Fixed: Crash while deleting in-use enumeration
-* Fixed: Hard coded English string at the selection of issue watchers
-* Fixed: Bazaar v2.1.0 changed behaviour
-* Fixed: Roadmap display can raise an exception if no trackers are selected
-* Fixed: Gravatar breaks layout of "logged in" page
-* Fixed: Reposman.rb on Windows
-* Fixed: Possible error 500 while moving an issue to another project with SQLite
-* Fixed: backslashes in issue description/note should be escaped when quoted
-* Fixed: Long text in disrupts Associated revisions
-* Fixed: Links to missing wiki pages not red on project overview page
-* Fixed: Cannot delete a project with subprojects that shares versions
-* Fixed: Update of Subversion changesets broken under Solaris
-* Fixed: "Move issues" permission not working for Non member
-* Fixed: Sidebar overlap on Users tab of Group editor
-* Fixed: Error on db:migrate with table prefix set (hardcoded name in principal.rb)
-* Fixed: Report shows sub-projects for non-members
-* Fixed: 500 internal error when browsing any Redmine page in epiphany
-* Fixed: Watchers selection lost when issue creation fails
-* Fixed: When copying projects, redmine should not generate an email to people who created issues
-* Fixed: Issue "#" table cells should have a class attribute to enable fine-grained CSS theme
-* Fixed: Plugin generators should display help if no parameter is given
-
-
-== 2010-02-28 v0.9.3
-
-* Adds filter for system shared versions on the cross project issue list
-* Makes project identifiers searchable
-* Remove invalid utf8 sequences from commit comments and author name
-* Fixed: Wrong link when "http" not included in project "Homepage" link
-* Fixed: Escaping in html email templates
-* Fixed: Pound (#) followed by number with leading zero (0) removes leading zero when rendered in wiki
-* Fixed: Deselecting textile text formatting causes interning empty string errors
-* Fixed: error with postgres when entering a non-numeric id for an issue relation
-* Fixed: div.task incorrectly wrapping on Gantt Chart
-* Fixed: Project copy loses wiki pages hierarchy
-* Fixed: parent project field doesn't include blank value when a member with 'add subproject' permission edits a child project
-* Fixed: Repository.fetch_changesets tries to fetch changesets for archived projects
-* Fixed: Duplicated project name for subproject version on gantt chart
-* Fixed: roadmap shows subprojects issues even if subprojects is unchecked
-* Fixed: IndexError if all the :last menu items are deleted from a menu
-* Fixed: Very high CPU usage for a long time when fetching commits from a large Git repository
-
-
-== 2010-02-07 v0.9.2
-
-* Fixed: Sub-project repository commits not displayed on parent project issues
-* Fixed: Potential security leak on my page calendar
-* Fixed: Project tree structure is broken by deleting the project with the subproject
-* Fixed: Error message shown duplicated when creating a new group
-* Fixed: Firefox cuts off large pages
-* Fixed: Invalid format parameter returns a DoubleRenderError on issues index
-* Fixed: Unnecessary Quote button on locked forum message
-* Fixed: Error raised when trying to view the gantt or calendar with a grouped query
-* Fixed: PDF support for Korean locale
-* Fixed: Deprecation warning in extra/svn/reposman.rb
-
-
-== 2010-01-30 v0.9.1
-
-* Vertical alignment for inline images in formatted text set to 'middle'
-* Fixed: Redmine.pm error "closing dbh with active statement handles at /usr/lib/perl5/Apache/Redmine.pm"
-* Fixed: copyright year in footer set to 2010
-* Fixed: Trac migration script may not output query lines
-* Fixed: Email notifications may affect language of notice messages on the UI
-* Fixed: Can not search for 2 letters word
-* Fixed: Attachments get saved on issue update even if validation fails
-* Fixed: Tab's 'border-bottom' not absent when selected
-* Fixed: Issue summary tables that list by user are not sorted
-* Fixed: Issue pdf export fails if target version is set
-* Fixed: Issue list export to PDF breaks when issues are sorted by a custom field
-* Fixed: SQL error when adding a group
-* Fixes: Min password length during password reset always displays as 4 chars
-
-
-== 2010-01-09 v0.9.0 (Release candidate)
-
-* Unlimited subproject nesting
-* Multiple roles per user per project
-* User groups
-* Inheritence of versions
-* OpenID login
-* "Watched by me" issue filter
-* Project copy
-* Project creation by non admin users
-* Accept emails from anyone on a private project
-* Add email notification on Wiki changes
-* Make issue description non-required field
-* Custom fields for Versions
-* Being able to sort the issue list by custom fields
-* Ability to close versions
-* User display/editing of custom fields attached to their user profile
-* Add "follows" issue relation
-* Copy workflows between trackers and roles
-* Defaults enabled modules list for project creation
-* Weighted version completion percentage on the roadmap
-* Autocreate user account when user submits email that creates new issue
-* CSS class on overdue issues on the issue list
-* Enable tracker update on issue edit form
-* Remove issue watchers
-* Ability to move threads between project forums
-* Changed custom field "Possible values" to a textarea
-* Adds projects association on tracker form
-* Set session store to cookie store by default
-* Set a default wiki page on project creation
-* Roadmap for main project should see Roadmaps for sub projects
-* Ticket grouping on the issue list
-* Hierarchical Project links in the page header
-* Allow My Page blocks to be added to from a plugin
-* Sort issues by multiple columns
-* Filters of saved query are now visible and be adjusted without editing the query
-* Saving "sort order" in custom queries
-* Url to fetch changesets for a repository
-* Managers able to create subprojects
-* Issue Totals on My Page Modules
-* Convert Enumerations to single table inheritance (STI)
-* Allow custom my_page blocks to define drop-down names
-* "View Issues" user permission added
-* Ask user what to do with child pages when deleting a parent wiki page
-* Contextual quick search
-* Allow resending of password by email
-* Change reply subject to be a link to the reply itself
-* Include Logged Time as part of the project's Activity history
-* REST API for authentication
-* Browse through Git branches
-* Setup Object Daddy to replace test fixtures
-* Setup shoulda to make it easier to test
-* Custom fields and overrides on Enumerations
-* Add or remove columns from the issue list
-* Ability to add new version from issues screen
-* Setting to choose which day calendars start
-* Asynchronous email delivery method
-* RESTful URLs for (almost) everything
-* Include issue status in search results and activity pages
-* Add email to admin user search filter
-* Proper content type for plain text mails
-* Default value of project jump box
-* Tree based menus
-* Ability to use issue status to update percent done
-* Second set of issue "Action Links" at the bottom of an issue page
-* Proper exist status code for rdm-mailhandler.rb
-* Remove incoming email body via a delimiter
-* Fixed: Custom querry 'Export to PDF' ignores field selection
-* Fixed: Related e-mail notifications aren't threaded
-* Fixed: No warning when the creation of a categories from the issue form fails
-* Fixed: Actually block issues from closing when relation 'blocked by' isn't closed
-* Fixed: Include both first and last name when sorting by users
-* Fixed: Table cell with multiple line text
-* Fixed: Project overview page shows disabled trackers
-* Fixed: Cross project issue relations and user permissions
-* Fixed: My page shows tickets the user doesn't have access to
-* Fixed: TOC does not parse wiki page reference links with description
-* Fixed: Target version-list on bulk edit form is incorrectly sorted
-* Fixed: Cannot modify/delete project named "Documents"
-* Fixed: Email address in brackets breaks html
-* Fixed: Timelog detail loose issue filter passing to report tab
-* Fixed: Inform about custom field's name maximum length
-* Fixed: Activity page and Atom feed links contain project id instead of identifier
-* Fixed: no Atom key for forums with only 1 forum
-* Fixed: When reading RSS feed in MS Outlook, the inline links are broken.
-* Fixed: Sometimes new posts don't show up in the topic list of a forum.
-* Fixed: The all/active filter selection in the project view does not stick.
-* Fixed: Login box has Different width
-* Fixed: User removed from project - still getting project update emails
-* Fixed: Project with the identifier of 'new' cannot be viewed
-* Fixed: Artefacts in search view (Cyrillic)
-* Fixed: Allow [#id] as subject to reply by email
-* Fixed: Wrong language used when closing an issue via a commit message
-* Fixed: email handler drops emails for new issues with no subject
-* Fixed: Calendar misspelled under Roles/Permissions
-* Fixed: Emails from no-reply redmine's address hell cycle
-* Fixed: child_pages macro fails on wiki page history
-* Fixed: Pre-filled time tracking date ignores timezone
-* Fixed: Links on locked users lead to 404 page
-* Fixed: Page changes in issue-list when using context menu
-* Fixed: diff parser removes lines starting with multiple dashes
-* Fixed: Quoting in forums resets message subject
-* Fixed: Editing issue comment removes quote link
-* Fixed: Redmine.pm ignore browse_repository permission
-* Fixed: text formatting breaks on [msg1][msg2]
-* Fixed: Spent Time Default Value of 0.0
-* Fixed: Wiki pages in search results are referenced by project number, not by project identifier.
-* Fixed: When logging in via an autologin cookie the user's last_login_on should be updated
-* Fixed: 50k users cause problems in project->settings->members screen
-* Fixed: Document timestamp needs to show updated timestamps
-* Fixed: Users getting notifications for issues they are no longer allowed to view
-* Fixed: issue summary counts should link to the issue list without subprojects
-* Fixed: 'Delete' link on LDAP list has no effect
-
-
-== 2009-11-15 v0.8.7
-
-* Fixed: Hide paragraph terminator at the end of headings on html export
-* Fixed: pre tags containing " at the beginning of lines
-* Adds a Reply link to each issue note
-* Adds plain text only option for mail notifications
-* Gravatar support for issue detail, user grid, and activity stream (disabled by default)
-* Adds 'Delete wiki pages attachments' permission
-* Show the most recent file when displaying an inline image
-* Makes permission screens localized
-* AuthSource list: display associated users count and disable 'Delete' buton if any
-* Make the 'duplicates of' relation asymmetric
-* Adds username to the password reminder email
-* Adds links to forum messages using message#id syntax
-* Allow same name for custom fields on different object types
-* One-click bulk edition using the issue list context menu within the same project
-* Adds support for commit logs reencoding to UTF-8 before insertion in the database. Source encoding of commit logs can be selected in Application settings -> Repositories.
-* Adds checkboxes toggle links on permissions report
-* Adds Trac-Like anchors on wiki headings
-* Adds support for wiki links with anchor
-* Adds category to the issue context menu
-* Adds a workflow overview screen
-* Appends the filename to the attachment url so that clients that ignore content-disposition http header get the real filename
-* Dots allowed in custom field name
-* Adds posts quoting functionality
-* Adds an option to generate sequential project identifiers
-* Adds mailto link on the user administration list
-* Ability to remove enumerations (activities, priorities, document categories) that are in use. Associated objects can be reassigned to another value
-* Gantt chart: display issues that don't have a due date if they are assigned to a version with a date
-* Change projects homepage limit to 255 chars
-* Improved on-the-fly account creation. If some attributes are missing (eg. not present in the LDAP) or are invalid, the registration form is displayed so that the user is able to fill or fix these attributes
-* Adds "please select" to activity select box if no activity is set as default
-* Do not silently ignore timelog validation failure on issue edit
-* Adds a rake task to send reminder emails
-* Allow empty cells in wiki tables
-* Makes wiki text formatter pluggable
-* Adds back textile acronyms support
-* Remove pre tag attributes
-* Plugin hooks
-* Pluggable admin menu
-* Plugins can provide activity content
-* Moves plugin list to its own administration menu item
-* Adds url and author_url plugin attributes
-* Adds Plugin#requires_redmine method so that plugin compatibility can be checked against current Redmine version
-* Adds atom feed on time entries details
-* Adds project name to issues feed title
-* Adds a css class on menu items in order to apply item specific styles (eg. icons)
-* Adds a Redmine plugin generators
-* Adds timelog link to the issue context menu
-* Adds links to the user page on various views
-* Turkish translation by Ismail Sezen
-* Catalan translation
-* Vietnamese translation
-* Slovak translation
-* Better naming of activity feed if only one kind of event is displayed
-* Enable syntax highlight on issues, messages and news
-* Add target version to the issue list context menu
-* Hide 'Target version' filter if no version is defined
-* Add filters on cross-project issue list for custom fields marked as 'For all projects'
-* Turn ftp urls into links
-* Hiding the View Differences button when a wiki page's history only has one version
-* Messages on a Board can now be sorted by the number of replies
-* Adds a class ('me') to events of the activity view created by current user
-* Strip pre/code tags content from activity view events
-* Display issue notes in the activity view
-* Adds links to changesets atom feed on repository browser
-* Track project and tracker changes in issue history
-* Adds anchor to atom feed messages links
-* Adds a key in lang files to set the decimal separator (point or comma) in csv exports
-* Makes importer work with Trac 0.8.x
-* Upgraded to Prototype 1.6.0.1
-* File viewer for attached text files
-* Menu mapper: add support for :before, :after and :last options to #push method and add #delete method
-* Removed inconsistent revision numbers on diff view
-* CVS: add support for modules names with spaces
-* Log the user in after registration if account activation is not needed
-* Mercurial adapter improvements
-* Trac importer: read session_attribute table to find user's email and real name
-* Ability to disable unused SCM adapters in application settings
-* Adds Filesystem adapter
-* Clear changesets and changes with raw sql when deleting a repository for performance
-* Redmine.pm now uses the 'commit access' permission defined in Redmine
-* Reposman can create any type of scm (--scm option)
-* Reposman creates a repository if the 'repository' module is enabled at project level only
-* Display svn properties in the browser, svn >= 1.5.0 only
-* Reduces memory usage when importing large git repositories
-* Wider SVG graphs in repository stats
-* SubversionAdapter#entries performance improvement
-* SCM browser: ability to download raw unified diffs
-* More detailed error message in log when scm command fails
-* Adds support for file viewing with Darcs 2.0+
-* Check that git changeset is not in the database before creating it
-* Unified diff viewer for attached files with .patch or .diff extension
-* File size display with Bazaar repositories
-* Git adapter: use commit time instead of author time
-* Prettier url for changesets
-* Makes changes link to entries on the revision view
-* Adds a field on the repository view to browse at specific revision
-* Adds new projects atom feed
-* Added rake tasks to generate rcov code coverage reports
-* Add Redcloth's :block_markdown_rule to allow horizontal rules in wiki
-* Show the project hierarchy in the drop down list for new membership on user administration screen
-* Split user edit screen into tabs
-* Renames bundled RedCloth to RedCloth3 to avoid RedCloth 4 to be loaded instead
-* Fixed: Roadmap crashes when a version has a due date > 2037
-* Fixed: invalid effective date (eg. 99999-01-01) causes an error on version edition screen
-* Fixed: login filter providing incorrect back_url for Redmine installed in sub-directory
-* Fixed: logtime entry duplicated when edited from parent project
-* Fixed: wrong digest for text files under Windows
-* Fixed: associated revisions are displayed in wrong order on issue view
-* Fixed: Git Adapter date parsing ignores timezone
-* Fixed: Printing long roadmap doesn't split across pages
-* Fixes custom fields display order at several places
-* Fixed: urls containing @ are parsed as email adress by the wiki formatter
-* Fixed date filters accuracy with SQLite
-* Fixed: tokens not escaped in highlight_tokens regexp
-* Fixed Bazaar shared repository browsing
-* Fixes platform determination under JRuby
-* Fixed: Estimated time in issue's journal should be rounded to two decimals
-* Fixed: 'search titles only' box ignored after one search is done on titles only
-* Fixed: non-ASCII subversion path can't be displayed
-* Fixed: Inline images don't work if file name has upper case letters or if image is in BMP format
-* Fixed: document listing shows on "my page" when viewing documents is disabled for the role
-* Fixed: Latest news appear on the homepage for projects with the News module disabled
-* Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled
-* Fixed: the default status is lost when reordering issue statuses
-* Fixes error with Postgresql and non-UTF8 commit logs
-* Fixed: textile footnotes no longer work
-* Fixed: http links containing parentheses fail to reder correctly
-* Fixed: GitAdapter#get_rev should use current branch instead of hardwiring master
-
-
-== 2008-07-06 v0.7.3
-
-* Allow dot in firstnames and lastnames
-* Add project name to cross-project Atom feeds
-* Encoding set to utf8 in example database.yml
-* HTML titles on forums related views
-* Fixed: various XSS vulnerabilities
-* Fixed: Entourage (and some old client) fails to correctly render notification styles
-* Fixed: Fixed: timelog redirects inappropriately when :back_url is blank
-* Fixed: wrong relative paths to images in wiki_syntax.html
-
-
-== 2008-06-15 v0.7.2
-
-* "New Project" link on Projects page
-* Links to repository directories on the repo browser
-* Move status to front in Activity View
-* Remove edit step from Status context menu
-* Fixed: No way to do textile horizontal rule
-* Fixed: Repository: View differences doesn't work
-* Fixed: attachement's name maybe invalid.
-* Fixed: Error when creating a new issue
-* Fixed: NoMethodError on @available_filters.has_key?
-* Fixed: Check All / Uncheck All in Email Settings
-* Fixed: "View differences" of one file at /repositories/revision/ fails
-* Fixed: Column width in "my page"
-* Fixed: private subprojects are listed on Issues view
-* Fixed: Textile: bold, italics, underline, etc... not working after parentheses
-* Fixed: Update issue form: comment field from log time end out of screen
-* Fixed: Editing role: "issue can be assigned to this role" out of box
-* Fixed: Unable use angular braces after include word
-* Fixed: Using '*' as keyword for repository referencing keywords doesn't work
-* Fixed: Subversion repository "View differences" on each file rise ERROR
-* Fixed: View differences for individual file of a changeset fails if the repository URL doesn't point to the repository root
-* Fixed: It is possible to lock out the last admin account
-* Fixed: Wikis are viewable for anonymous users on public projects, despite not granting access
-* Fixed: Issue number display clipped on 'my issues'
-* Fixed: Roadmap version list links not carrying state
-* Fixed: Log Time fieldset in IssueController#edit doesn't set default Activity as default
-* Fixed: git's "get_rev" API should use repo's current branch instead of hardwiring "master"
-* Fixed: browser's language subcodes ignored
-* Fixed: Error on project selection with numeric (only) identifier.
-* Fixed: Link to PDF doesn't work after creating new issue
-* Fixed: "Replies" should not be shown on forum threads that are locked
-* Fixed: SVN errors lead to svn username/password being displayed to end users (security issue)
-* Fixed: http links containing hashes don't display correct
-* Fixed: Allow ampersands in Enumeration names
-* Fixed: Atom link on saved query does not include query_id
-* Fixed: Logtime info lost when there's an error updating an issue
-* Fixed: TOC does not parse colorization markups
-* Fixed: CVS: add support for modules names with spaces
-* Fixed: Bad rendering on projects/add
-* Fixed: exception when viewing differences on cvs
-* Fixed: export issue to pdf will messup when use Chinese language
-* Fixed: Redmine::Scm::Adapters::GitAdapter#get_rev ignored GIT_BIN constant
-* Fixed: Adding non-ASCII new issue type in the New Issue page have encoding error using IE
-* Fixed: Importing from trac : some wiki links are messed
-* Fixed: Incorrect weekend definition in Hebrew calendar locale
-* Fixed: Atom feeds don't provide author section for repository revisions
-* Fixed: In Activity views, changesets titles can be multiline while they should not
-* Fixed: Ignore unreadable subversion directories (read disabled using authz)
-* Fixed: lib/SVG/Graph/Graph.rb can't externalize stylesheets
-* Fixed: Close statement handler in Redmine.pm
-
-
-== 2008-05-04 v0.7.1
-
-* Thai translation added (Gampol Thitinilnithi)
-* Translations updates
-* Escape HTML comment tags
-* Prevent "can't convert nil into String" error when :sort_order param is not present
-* Fixed: Updating tickets add a time log with zero hours
-* Fixed: private subprojects names are revealed on the project overview
-* Fixed: Search for target version of "none" fails with postgres 8.3
-* Fixed: Home, Logout, Login links shouldn't be absolute links
-* Fixed: 'Latest projects' box on the welcome screen should be hidden if there are no projects
-* Fixed: error when using upcase language name in coderay
-* Fixed: error on Trac import when :due attribute is nil
-
-
-== 2008-04-28 v0.7.0
-
-* Forces Redmine to use rails 2.0.2 gem when vendor/rails is not present
-* Queries can be marked as 'For all projects'. Such queries will be available on all projects and on the global issue list.
-* Add predefined date ranges to the time report
-* Time report can be done at issue level
-* Various timelog report enhancements
-* Accept the following formats for "hours" field: 1h, 1 h, 1 hour, 2 hours, 30m, 30min, 1h30, 1h30m, 1:30
-* Display the context menu above and/or to the left of the click if needed
-* Make the admin project files list sortable
-* Mercurial: display working directory files sizes unless browsing a specific revision
-* Preserve status filter and page number when using lock/unlock/activate links on the users list
-* Redmine.pm support for LDAP authentication
-* Better error message and AR errors in log for failed LDAP on-the-fly user creation
-* Redirected user to where he is coming from after logging hours
-* Warn user that subprojects are also deleted when deleting a project
-* Include subprojects versions on calendar and gantt
-* Notify project members when a message is posted if they want to receive notifications
-* Fixed: Feed content limit setting has no effect
-* Fixed: Priorities not ordered when displayed as a filter in issue list
-* Fixed: can not display attached images inline in message replies
-* Fixed: Boards are not deleted when project is deleted
-* Fixed: trying to preview a new issue raises an exception with postgresql
-* Fixed: single file 'View difference' links do not work because of duplicate slashes in url
-* Fixed: inline image not displayed when including a wiki page
-* Fixed: CVS duplicate key violation
-* Fixed: ActiveRecord::StaleObjectError exception on closing a set of circular duplicate issues
-* Fixed: custom field filters behaviour
-* Fixed: Postgresql 8.3 compatibility
-* Fixed: Links to repository directories don't work
-
-
-== 2008-03-29 v0.7.0-rc1
-
-* Overall activity view and feed added, link is available on the project list
-* Git VCS support
-* Rails 2.0 sessions cookie store compatibility
-* Use project identifiers in urls instead of ids
-* Default configuration data can now be loaded from the administration screen
-* Administration settings screen split to tabs (email notifications options moved to 'Settings')
-* Project description is now unlimited and optional
-* Wiki annotate view
-* Escape HTML tag in textile content
-* Add Redmine links to documents, versions, attachments and repository files
-* New setting to specify how many objects should be displayed on paginated lists. There are 2 ways to select a set of issues on the issue list:
- * by using checkbox and/or the little pencil that will select/unselect all issues
- * by clicking on the rows (but not on the links), Ctrl and Shift keys can be used to select multiple issues
-* Context menu disabled on links so that the default context menu of the browser is displayed when right-clicking on a link (click anywhere else on the row to display the context menu)
-* User display format is now configurable in administration settings
-* Issue list now supports bulk edit/move/delete (for a set of issues that belong to the same project)
-* Merged 'change status', 'edit issue' and 'add note' actions:
- * Users with 'edit issues' permission can now update any property including custom fields when adding a note or changing the status
- * 'Change issue status' permission removed. To change an issue status, a user just needs to have either 'Edit' or 'Add note' permissions and some workflow transitions allowed
-* Details by assignees on issue summary view
-* 'New issue' link in the main menu (accesskey 7). The drop-down lists to add an issue on the project overview and the issue list are removed
-* Change status select box default to current status
-* Preview for issue notes, news and messages
-* Optional description for attachments
-* 'Fixed version' label changed to 'Target version'
-* Let the user choose when deleting issues with reported hours to:
- * delete the hours
- * assign the hours to the project
- * reassign the hours to another issue
-* Date range filter and pagination on time entries detail view
-* Propagate time tracking to the parent project
-* Switch added on the project activity view to include subprojects
-* Display total estimated and spent hours on the version detail view
-* Weekly time tracking block for 'My page'
-* Permissions to edit time entries
-* Include subprojects on the issue list, calendar, gantt and timelog by default (can be turned off is administration settings)
-* Roadmap enhancements (separate related issues from wiki contents, leading h1 in version wiki pages is hidden, smaller wiki headings)
-* Make versions with same date sorted by name
-* Allow issue list to be sorted by target version
-* Related changesets messages displayed on the issue details view
-* Create a journal and send an email when an issue is closed by commit
-* Add 'Author' to the available columns for the issue list
-* More appropriate default sort order on sortable columns
-* Add issue subject to the time entries view and issue subject, description and tracker to the csv export
-* Permissions to edit issue notes
-* Display date/time instead of date on files list
-* Do not show Roadmap menu item if the project doesn't define any versions
-* Allow longer version names (60 chars)
-* Ability to copy an existing workflow when creating a new role
-* Display custom fields in two columns on the issue form
-* Added 'estimated time' in the csv export of the issue list
-* Display the last 30 days on the activity view rather than the current month (number of days can be configured in the application settings)
-* Setting for whether new projects should be public by default
-* User preference to choose how comments/replies are displayed: in chronological or reverse chronological order
-* Added default value for custom fields
-* Added tabindex property on wiki toolbar buttons (to easily move from field to field using the tab key)
-* Redirect to issue page after creating a new issue
-* Wiki toolbar improvements (mainly for Firefox)
-* Display wiki syntax quick ref link on all wiki textareas
-* Display links to Atom feeds
-* Breadcrumb nav for the forums
-* Show replies when choosing to display messages in the activity
-* Added 'include' macro to include another wiki page
-* RedmineWikiFormatting page available as a static HTML file locally
-* Wrap diff content
-* Strip out email address from authors in repository screens
-* Highlight the current item of the main menu
-* Added simple syntax highlighters for php and java languages
-* Do not show empty diffs
-* Show explicit error message when the scm command failed (eg. when svn binary is not available)
-* Lithuanian translation added (Sergej Jegorov)
-* Ukrainan translation added (Natalia Konovka & Mykhaylo Sorochan)
-* Danish translation added (Mads Vestergaard)
-* Added i18n support to the jstoolbar and various settings screen
-* RedCloth's glyphs no longer user
-* New icons for the wiki toolbar (from http://www.famfamfam.com/lab/icons/silk/)
-* The following menus can now be extended by plugins: top_menu, account_menu, application_menu
-* Added a simple rake task to fetch changesets from the repositories: rake redmine:fetch_changesets
-* Remove hardcoded "Redmine" strings in account related emails and use application title instead
-* Mantis importer preserve bug ids
-* Trac importer: Trac guide wiki pages skipped
-* Trac importer: wiki attachments migration added
-* Trac importer: support database schema for Trac migration
-* Trac importer: support CamelCase links
-* Removes the Redmine version from the footer (can be viewed on admin -> info)
-* Rescue and display an error message when trying to delete a role that is in use
-* Add various 'X-Redmine' headers to email notifications: X-Redmine-Host, X-Redmine-Site, X-Redmine-Project, X-Redmine-Issue-Id, -Author, -Assignee, X-Redmine-Topic-Id
-* Add "--encoding utf8" option to the Mercurial "hg log" command in order to get utf8 encoded commit logs
-* Fixed: Gantt and calendar not properly refreshed (fragment caching removed)
-* Fixed: Textile image with style attribute cause internal server error
-* Fixed: wiki TOC not rendered properly when used in an issue or document description
-* Fixed: 'has already been taken' error message on username and email fields if left empty
-* Fixed: non-ascii attachement filename with IE
-* Fixed: wrong url for wiki syntax pop-up when Redmine urls are prefixed
-* Fixed: search for all words doesn't work
-* Fixed: Do not show sticky and locked checkboxes when replying to a message
-* Fixed: Mantis importer: do not duplicate Mantis username in firstname and lastname if realname is blank
-* Fixed: Date custom fields not displayed as specified in application settings
-* Fixed: titles not escaped in the activity view
-* Fixed: issue queries can not use custom fields marked as 'for all projects' in a project context
-* Fixed: on calendar, gantt and in the tracker filter on the issue list, only active trackers of the project (and its sub projects) should be available
-* Fixed: locked users should not receive email notifications
-* Fixed: custom field selection is not saved when unchecking them all on project settings
-* Fixed: can not lock a topic when creating it
-* Fixed: Incorrect filtering for unset values when using 'is not' filter
-* Fixed: PostgreSQL issues_seq_id not updated when using Trac importer
-* Fixed: ajax pagination does not scroll up
-* Fixed: error when uploading a file with no content-type specified by the browser
-* Fixed: wiki and changeset links not displayed when previewing issue description or notes
-* Fixed: 'LdapError: no bind result' error when authenticating
-* Fixed: 'LdapError: invalid binding information' when no username/password are set on the LDAP account
-* Fixed: CVS repository doesn't work if port is used in the url
-* Fixed: Email notifications: host name is missing in generated links
-* Fixed: Email notifications: referenced changesets, wiki pages, attachments... are not turned into links
-* Fixed: Do not clear issue relations when moving an issue to another project if cross-project issue relations are allowed
-* Fixed: "undefined method 'textilizable'" error on email notification when running Repository#fetch_changesets from the console
-* Fixed: Do not send an email with no recipient, cc or bcc
-* Fixed: fetch_changesets fails on commit comments that close 2 duplicates issues.
-* Fixed: Mercurial browsing under unix-like os and for directory depth > 2
-* Fixed: Wiki links with pipe can not be used in wiki tables
-* Fixed: migrate_from_trac doesn't import timestamps of wiki and tickets
-* Fixed: when bulk editing, setting "Assigned to" to "nobody" causes an sql error with Postgresql
-
-
-== 2008-03-12 v0.6.4
-
-* Fixed: private projects name are displayed on account/show even if the current user doesn't have access to these private projects
-* Fixed: potential LDAP authentication security flaw
-* Fixed: context submenus on the issue list don't show up with IE6.
-* Fixed: Themes are not applied with Rails 2.0
-* Fixed: crash when fetching Mercurial changesets if changeset[:files] is nil
-* Fixed: Mercurial repository browsing
-* Fixed: undefined local variable or method 'log' in CvsAdapter when a cvs command fails
-* Fixed: not null constraints not removed with Postgresql
-* Doctype set to transitional
-
-
-== 2007-12-18 v0.6.3
-
-* Fixed: upload doesn't work in 'Files' section
-
-
-== 2007-12-16 v0.6.2
-
-* Search engine: issue custom fields can now be searched
-* News comments are now textilized
-* Updated Japanese translation (Satoru Kurashiki)
-* Updated Chinese translation (Shortie Lo)
-* Fixed Rails 2.0 compatibility bugs:
- * Unable to create a wiki
- * Gantt and calendar error
- * Trac importer error (readonly? is defined by ActiveRecord)
-* Fixed: 'assigned to me' filter broken
-* Fixed: crash when validation fails on issue edition with no custom fields
-* Fixed: reposman "can't find group" error
-* Fixed: 'LDAP account password is too long' error when leaving the field empty on creation
-* Fixed: empty lines when displaying repository files with Windows style eol
-* Fixed: missing body closing tag in repository annotate and entry views
-
-
-== 2007-12-10 v0.6.1
-
-* Rails 2.0 compatibility
-* Custom fields can now be displayed as columns on the issue list
-* Added version details view (accessible from the roadmap)
-* Roadmap: more accurate completion percentage calculation (done ratio of open issues is now taken into account)
-* Added per-project tracker selection. Trackers can be selected on project settings
-* Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums
-* Forums: messages can now be edited/deleted (explicit permissions need to be given)
-* Forums: topics can be locked so that no reply can be added
-* Forums: topics can be marked as sticky so that they always appear at the top of the list
-* Forums: attachments can now be added to replies
-* Added time zone support
-* Added a setting to choose the account activation strategy (available in application settings)
-* Added 'Classic' theme (inspired from the v0.51 design)
-* Added an alternate theme which provides issue list colorization based on issues priority
-* Added Bazaar SCM adapter
-* Added Annotate/Blame view in the repository browser (except for Darcs SCM)
-* Diff style (inline or side by side) automatically saved as a user preference
-* Added issues status changes on the activity view (by Cyril Mougel)
-* Added forums topics on the activity view (disabled by default)
-* Added an option on 'My account' for users who don't want to be notified of changes that they make
-* Trac importer now supports mysql and postgresql databases
-* Trac importer improvements (by Mat Trudel)
-* 'fixed version' field can now be displayed on the issue list
-* Added a couple of new formats for the 'date format' setting
-* Added Traditional Chinese translation (by Shortie Lo)
-* Added Russian translation (iGor kMeta)
-* Project name format limitation removed (name can now contain any character)
-* Project identifier maximum length changed from 12 to 20
-* Changed the maximum length of LDAP account to 255 characters
-* Removed the 12 characters limit on passwords
-* Added wiki macros support
-* Performance improvement on workflow setup screen
-* More detailed html title on several views
-* Custom fields can now be reordered
-* Search engine: search can be restricted to an exact phrase by using quotation marks
-* Added custom fields marked as 'For all projects' to the csv export of the cross project issue list
-* Email notifications are now sent as Blind carbon copy by default
-* Fixed: all members (including non active) should be deleted when deleting a project
-* Fixed: Error on wiki syntax link (accessible from wiki/edit)
-* Fixed: 'quick jump to a revision' form on the revisions list
-* Fixed: error on admin/info if there's more than 1 plugin installed
-* Fixed: svn or ldap password can be found in clear text in the html source in editing mode
-* Fixed: 'Assigned to' drop down list is not sorted
-* Fixed: 'View all issues' link doesn't work on issues/show
-* Fixed: error on account/register when validation fails
-* Fixed: Error when displaying the issue list if a float custom field is marked as 'used as filter'
-* Fixed: Mercurial adapter breaks on missing :files entry in changeset hash (James Britt)
-* Fixed: Wrong feed URLs on the home page
-* Fixed: Update of time entry fails when the issue has been moved to an other project
-* Fixed: Error when moving an issue without changing its tracker (Postgresql)
-* Fixed: Changes not recorded when using :pserver string (CVS adapter)
-* Fixed: admin should be able to move issues to any project
-* Fixed: adding an attachment is not possible when changing the status of an issue
-* Fixed: No mime-types in documents/files downloading
-* Fixed: error when sorting the messages if there's only one board for the project
-* Fixed: 'me' doesn't appear in the drop down filters on a project issue list.
-
-== 2007-11-04 v0.6.0
-
-* Permission model refactoring.
-* Permissions: there are now 2 builtin roles that can be used to specify permissions given to other users than members of projects
-* Permissions: some permissions (eg. browse the repository) can be removed for certain roles
-* Permissions: modules (eg. issue tracking, news, documents...) can be enabled/disabled at project level
-* Added Mantis and Trac importers
-* New application layout
-* Added "Bulk edit" functionality on the issue list
-* More flexible mail notifications settings at user level
-* Added AJAX based context menu on the project issue list that provide shortcuts for editing, re-assigning, changing the status or the priority, moving or deleting an issue
-* Added the hability to copy an issue. It can be done from the "issue/show" view or from the context menu on the issue list
-* Added the ability to customize issue list columns (at application level or for each saved query)
-* Overdue versions (date reached and open issues > 0) are now always displayed on the roadmap
-* Added the ability to rename wiki pages (specific permission required)
-* Search engines now supports pagination. Results are sorted in reverse chronological order
-* Added "Estimated hours" attribute on issues
-* A category with assigned issue can now be deleted. 2 options are proposed: remove assignments or reassign issues to another category
-* Forum notifications are now also sent to the authors of the thread, even if they don�t watch the board
-* Added an application setting to specify the application protocol (http or https) used to generate urls in emails
-* Gantt chart: now starts at the current month by default
-* Gantt chart: month count and zoom factor are automatically saved as user preferences
-* Wiki links can now refer to other project wikis
-* Added wiki index by date
-* Added preview on add/edit issue form
-* Emails footer can now be customized from the admin interface (Admin -> Email notifications)
-* Default encodings for repository files can now be set in application settings (used to convert files content and diff to UTF-8 so that they�re properly displayed)
-* Calendar: first day of week can now be set in lang files
-* Automatic closing of duplicate issues
-* Added a cross-project issue list
-* AJAXified the SCM browser (tree view)
-* Pretty URL for the repository browser (Cyril Mougel)
-* Search engine: added a checkbox to search titles only
-* Added "% done" in the filter list
-* Enumerations: values can now be reordered and a default value can be specified (eg. default issue priority)
-* Added some accesskeys
-* Added "Float" as a custom field format
-* Added basic Theme support
-* Added the ability to set the �done ratio� of issues fixed by commit (Nikolay Solakov)
-* Added custom fields in issue related mail notifications
-* Email notifications are now sent in plain text and html
-* Gantt chart can now be exported to a graphic file (png). This functionality is only available if RMagick is installed.
-* Added syntax highlightment for repository files and wiki
-* Improved automatic Redmine links
-* Added automatic table of content support on wiki pages
-* Added radio buttons on the documents list to sort documents by category, date, title or author
-* Added basic plugin support, with a sample plugin
-* Added a link to add a new category when creating or editing an issue
-* Added a "Assignable" boolean on the Role model. If unchecked, issues can not be assigned to users having this role.
-* Added an option to be able to relate issues in different projects
-* Added the ability to move issues (to another project) without changing their trackers.
-* Atom feeds added on project activity, news and changesets
-* Added the ability to reset its own RSS access key
-* Main project list now displays root projects with their subprojects
-* Added anchor links to issue notes
-* Added reposman Ruby version. This script can now register created repositories in Redmine (Nicolas Chuche)
-* Issue notes are now included in search
-* Added email sending test functionality
-* Added LDAPS support for LDAP authentication
-* Removed hard-coded URLs in mail templates
-* Subprojects are now grouped by projects in the navigation drop-down menu
-* Added a new value for date filters: this week
-* Added cache for application settings
-* Added Polish translation (Tomasz Gawryl)
-* Added Czech translation (Jan Kadlecek)
-* Added Romanian translation (Csongor Bartus)
-* Added Hebrew translation (Bob Builder)
-* Added Serbian translation (Dragan Matic)
-* Added Korean translation (Choi Jong Yoon)
-* Fixed: the link to delete issue relations is displayed even if the user is not authorized to delete relations
-* Performance improvement on calendar and gantt
-* Fixed: wiki preview doesn�t work on long entries
-* Fixed: queries with multiple custom fields return no result
-* Fixed: Can not authenticate user against LDAP if its DN contains non-ascii characters
-* Fixed: URL with ~ broken in wiki formatting
-* Fixed: some quotation marks are rendered as strange characters in pdf
-
-
-== 2007-07-15 v0.5.1
-
-* per project forums added
-* added the ability to archive projects
-* added �Watch� functionality on issues. It allows users to receive notifications about issue changes
-* custom fields for issues can now be used as filters on issue list
-* added per user custom queries
-* commit messages are now scanned for referenced or fixed issue IDs (keywords defined in Admin -> Settings)
-* projects list now shows the list of public projects and private projects for which the user is a member
-* versions can now be created with no date
-* added issue count details for versions on Reports view
-* added time report, by member/activity/tracker/version and year/month/week for the selected period
-* each category can now be associated to a user, so that new issues in that category are automatically assigned to that user
-* added autologin feature (disabled by default)
-* optimistic locking added for wiki edits
-* added wiki diff
-* added the ability to destroy wiki pages (requires permission)
-* a wiki page can now be attached to each version, and displayed on the roadmap
-* attachments can now be added to wiki pages (original patch by Pavol Murin) and displayed online
-* added an option to see all versions in the roadmap view (including completed ones)
-* added basic issue relations
-* added the ability to log time when changing an issue status
-* account information can now be sent to the user when creating an account
-* author and assignee of an issue always receive notifications (even if they turned of mail notifications)
-* added a quick search form in page header
-* added 'me' value for 'assigned to' and 'author' query filters
-* added a link on revision screen to see the entire diff for the revision
-* added last commit message for each entry in repository browser
-* added the ability to view a file diff with free to/from revision selection.
-* text files can now be viewed online when browsing the repository
-* added basic support for other SCM: CVS (Ralph Vater), Mercurial and Darcs
-* added fragment caching for svn diffs
-* added fragment caching for calendar and gantt views
-* login field automatically focused on login form
-* subproject name displayed on issue list, calendar and gantt
-* added an option to choose the date format: language based or ISO 8601
-* added a simple mail handler. It lets users add notes to an existing issue by replying to the initial notification email.
-* a 403 error page is now displayed (instead of a blank page) when trying to access a protected page
-* added portuguese translation (Joao Carlos Clementoni)
-* added partial online help japanese translation (Ken Date)
-* added bulgarian translation (Nikolay Solakov)
-* added dutch translation (Linda van den Brink)
-* added swedish translation (Thomas Habets)
-* italian translation update (Alessio Spadaro)
-* japanese translation update (Satoru Kurashiki)
-* fixed: error on history atom feed when there�s no notes on an issue change
-* fixed: error in journalizing an issue with longtext custom fields (Postgresql)
-* fixed: creation of Oracle schema
-* fixed: last day of the month not included in project activity
-* fixed: files with an apostrophe in their names can't be accessed in SVN repository
-* fixed: performance issue on RepositoriesController#revisions when a changeset has a great number of changes (eg. 100,000)
-* fixed: open/closed issue counts are always 0 on reports view (postgresql)
-* fixed: date query filters (wrong results and sql error with postgresql)
-* fixed: confidentiality issue on account/show (private project names displayed to anyone)
-* fixed: Long text custom fields displayed without line breaks
-* fixed: Error when editing the wokflow after deleting a status
-* fixed: SVN commit dates are now stored as local time
-
-
-== 2007-04-11 v0.5.0
-
-* added per project Wiki
-* added rss/atom feeds at project level (custom queries can be used as feeds)
-* added search engine (search in issues, news, commits, wiki pages, documents)
-* simple time tracking functionality added
-* added version due dates on calendar and gantt
-* added subprojects issue count on project Reports page
-* added the ability to copy an existing workflow when creating a new tracker
-* added the ability to include subprojects on calendar and gantt
-* added the ability to select trackers to display on calendar and gantt (Jeffrey Jones)
-* added side by side svn diff view (Cyril Mougel)
-* added back subproject filter on issue list
-* added permissions report in admin area
-* added a status filter on users list
-* support for password-protected SVN repositories
-* SVN commits are now stored in the database
-* added simple svn statistics SVG graphs
-* progress bars for roadmap versions (Nick Read)
-* issue history now shows file uploads and deletions
-* #id patterns are turned into links to issues in descriptions and commit messages
-* japanese translation added (Satoru Kurashiki)
-* chinese simplified translation added (Andy Wu)
-* italian translation added (Alessio Spadaro)
-* added scripts to manage SVN repositories creation and user access control using ssh+svn (Nicolas Chuche)
-* better calendar rendering time
-* fixed migration scripts to work with mysql 5 running in strict mode
-* fixed: error when clicking "add" with no block selected on my/page_layout
-* fixed: hard coded links in navigation bar
-* fixed: table_name pre/suffix support
-
-
-== 2007-02-18 v0.4.2
-
-* Rails 1.2 is now required
-* settings are now stored in the database and editable through the application in: Admin -> Settings (config_custom.rb is no longer used)
-* added project roadmap view
-* mail notifications added when a document, a file or an attachment is added
-* tooltips added on Gantt chart and calender to view the details of the issues
-* ability to set the sort order for roles, trackers, issue statuses
-* added missing fields to csv export: priority, start date, due date, done ratio
-* added total number of issues per tracker on project overview
-* all icons replaced (new icons are based on GPL icon set: "KDE Crystal Diamond 2.5" -by paolino- and "kNeu! Alpha v0.1" -by Pablo Fabregat-)
-* added back "fixed version" field on issue screen and in filters
-* project settings screen split in 4 tabs
-* custom fields screen split in 3 tabs (one for each kind of custom field)
-* multiple issues pdf export now rendered as a table
-* added a button on users/list to manually activate an account
-* added a setting option to disable "password lost" functionality
-* added a setting option to set max number of issues in csv/pdf exports
-* fixed: subprojects count is always 0 on projects list
-* fixed: locked users are proposed when adding a member to a project
-* fixed: setting an issue status as default status leads to an sql error with SQLite
-* fixed: unable to delete an issue status even if it's not used yet
-* fixed: filters ignored when exporting a predefined query to csv/pdf
-* fixed: crash when french "issue_edit" email notification is sent
-* fixed: hide mail preference not saved (my/account)
-* fixed: crash when a new user try to edit its "my page" layout
-
-
-== 2007-01-03 v0.4.1
-
-* fixed: emails have no recipient when one of the project members has notifications disabled
-
-
-== 2007-01-02 v0.4.0
-
-* simple SVN browser added (just needs svn binaries in PATH)
-* comments can now be added on news
-* "my page" is now customizable
-* more powerfull and savable filters for issues lists
-* improved issues change history
-* new functionality: move an issue to another project or tracker
-* new functionality: add a note to an issue
-* new report: project activity
-* "start date" and "% done" fields added on issues
-* project calendar added
-* gantt chart added (exportable to pdf)
-* single/multiple issues pdf export added
-* issues reports improvements
-* multiple file upload for issues, documents and files
-* option to set maximum size of uploaded files
-* textile formating of issue and news descritions (RedCloth required)
-* integration of DotClear jstoolbar for textile formatting
-* calendar date picker for date fields (LGPL DHTML Calendar http://sourceforge.net/projects/jscalendar)
-* new filter in issues list: Author
-* ajaxified paginators
-* news rss feed added
-* option to set number of results per page on issues list
-* localized csv separator (comma/semicolon)
-* csv output encoded to ISO-8859-1
-* user custom field displayed on account/show
-* default configuration improved (default roles, trackers, status, permissions and workflows)
-* language for default configuration data can now be chosen when running 'load_default_data' task
-* javascript added on custom field form to show/hide fields according to the format of custom field
-* fixed: custom fields not in csv exports
-* fixed: project settings now displayed according to user's permissions
-* fixed: application error when no version is selected on projects/add_file
-* fixed: public actions not authorized for members of non public projects
-* fixed: non public projects were shown on welcome screen even if current user is not a member
-
-
-== 2006-10-08 v0.3.0
-
-* user authentication against multiple LDAP (optional)
-* token based "lost password" functionality
-* user self-registration functionality (optional)
-* custom fields now available for issues, users and projects
-* new custom field format "text" (displayed as a textarea field)
-* project & administration drop down menus in navigation bar for quicker access
-* text formatting is preserved for long text fields (issues, projects and news descriptions)
-* urls and emails are turned into clickable links in long text fields
-* "due date" field added on issues
-* tracker selection filter added on change log
-* Localization plugin replaced with GLoc 1.1.0 (iconv required)
-* error messages internationalization
-* german translation added (thanks to Karim Trott)
-* data locking for issues to prevent update conflicts (using ActiveRecord builtin optimistic locking)
-* new filter in issues list: "Fixed version"
-* active filters are displayed with colored background on issues list
-* custom configuration is now defined in config/config_custom.rb
-* user object no more stored in session (only user_id)
-* news summary field is no longer required
-* tables and forms redesign
-* Fixed: boolean custom field not working
-* Fixed: error messages for custom fields are not displayed
-* Fixed: invalid custom fields should have a red border
-* Fixed: custom fields values are not validated on issue update
-* Fixed: unable to choose an empty value for 'List' custom fields
-* Fixed: no issue categories sorting
-* Fixed: incorrect versions sorting
-
-
-== 2006-07-12 - v0.2.2
-
-* Fixed: bug in "issues list"
-
-
-== 2006-07-09 - v0.2.1
-
-* new databases supported: Oracle, PostgreSQL, SQL Server
-* projects/subprojects hierarchy (1 level of subprojects only)
-* environment information display in admin/info
-* more filter options in issues list (rev6)
-* default language based on browser settings (Accept-Language HTTP header)
-* issues list exportable to CSV (rev6)
-* simple_format and auto_link on long text fields
-* more data validations
-* Fixed: error when all mail notifications are unchecked in admin/mail_options
-* Fixed: all project news are displayed on project summary
-* Fixed: Can't change user password in users/edit
-* Fixed: Error on tables creation with PostgreSQL (rev5)
-* Fixed: SQL error in "issue reports" view with PostgreSQL (rev5)
-
-
-== 2006-06-25 - v0.1.0
-
-* multiple users/multiple projects
-* role based access control
-* issue tracking system
-* fully customizable workflow
-* documents/files repository
-* email notifications on issue creation and update
-* multilanguage support (except for error messages):english, french, spanish
-* online manual in french (unfinished)
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/54/545f86d0a5e62f520b23fcd2c5c5da6a19591b51.svn-base
--- a/.svn/pristine/54/545f86d0a5e62f520b23fcd2c5c5da6a19591b51.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1010 +0,0 @@
-# Chinese (China) translations for Ruby on Rails
-# by tsechingho (http://github.com/tsechingho)
-zh:
- # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl)
- direction: ltr
- date:
- formats:
- # Use the strftime parameters for formats.
- # When no format has been given, it uses default.
- # You can provide other formats here if you like!
- default: "%Y-%m-%d"
- short: "%b%dæ—¥"
- long: "%Yå¹´%b%dæ—¥"
-
- day_names: [星期天, 星期一, 星期二, 星期三, 星期四, 星期五, 星期å…]
- abbr_day_names: [æ—¥, 一, 二, 三, å››, 五, å…]
-
- # Don't forget the nil at the beginning; there's no such thing as a 0th month
- month_names: [~, 一月, 二月, 三月, 四月, 五月, å…æœˆ, 七月, 八月, 乿œˆ, åæœˆ, å一月, å二月]
- abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
- # Used in date_select and datime_select.
- order:
- - :year
- - :month
- - :day
-
- time:
- formats:
- default: "%Yå¹´%b%dæ—¥ %A %H:%M:%S"
- time: "%H:%M"
- short: "%b%dæ—¥ %H:%M"
- long: "%Yå¹´%b%dæ—¥ %H:%M"
- am: "上åˆ"
- pm: "下åˆ"
-
- datetime:
- distance_in_words:
- half_a_minute: "åŠåˆ†é’Ÿ"
- less_than_x_seconds:
- one: "一秒内"
- other: "少于 %{count} 秒"
- x_seconds:
- one: "一秒"
- other: "%{count} ç§’"
- less_than_x_minutes:
- one: "一分钟内"
- other: "少于 %{count} 分钟"
- x_minutes:
- one: "一分钟"
- other: "%{count} 分钟"
- about_x_hours:
- one: "å¤§çº¦ä¸€å°æ—¶"
- other: "大约 %{count} å°æ—¶"
- x_days:
- one: "一天"
- other: "%{count} 天"
- about_x_months:
- one: "大约一个月"
- other: "大约 %{count} 个月"
- x_months:
- one: "一个月"
- other: "%{count} 个月"
- about_x_years:
- one: "大约一年"
- other: "大约 %{count} 年"
- over_x_years:
- one: "一年以上"
- other: "%{count} 年以上"
- almost_x_years:
- one: "将近 1 年"
- other: "将近 %{count} 年"
-
- number:
- # Default format for numbers
- format:
- separator: "."
- delimiter: ""
- precision: 3
- human:
- format:
- delimiter: ""
- precision: 1
- storage_units:
- format: "%n %u"
- units:
- byte:
- one: "Byte"
- other: "Bytes"
- kb: "kB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
-
-# Used in array.to_sentence.
- support:
- array:
- sentence_connector: "和"
- skip_last_comma: false
-
- activerecord:
- errors:
- template:
- header:
- one: "由于å‘生了一个错误 %{model} æ— æ³•ä¿å˜"
- other: "%{count} 个错误使得 %{model} æ— æ³•ä¿å˜"
- messages:
- inclusion: "ä¸åŒ…å«äºŽåˆ—表ä¸"
- exclusion: "是ä¿ç•™å…³é”®å—"
- invalid: "æ˜¯æ— æ•ˆçš„"
- confirmation: "与确认值ä¸åŒ¹é…"
- accepted: "必须是å¯è¢«æŽ¥å—çš„"
- empty: "ä¸èƒ½ç•™ç©º"
- blank: "ä¸èƒ½ä¸ºç©ºå—符"
- too_long: "过长(最长为 %{count} 个å—符)"
- too_short: "过çŸï¼ˆæœ€çŸä¸º %{count} 个å—符)"
- wrong_length: "é•¿åº¦éžæ³•(必须为 %{count} 个å—符)"
- taken: "å·²ç»è¢«ä½¿ç”¨"
- not_a_number: "䏿˜¯æ•°å—"
- not_a_date: "䏿˜¯åˆæ³•日期"
- greater_than: "必须大于 %{count}"
- greater_than_or_equal_to: "必须大于或ç‰äºŽ %{count}"
- equal_to: "å¿…é¡»ç‰äºŽ %{count}"
- less_than: "å¿…é¡»å°äºŽ %{count}"
- less_than_or_equal_to: "å¿…é¡»å°äºŽæˆ–ç‰äºŽ %{count}"
- odd: "å¿…é¡»ä¸ºå•æ•°"
- even: "å¿…é¡»ä¸ºåŒæ•°"
- greater_than_start_date: "必须在起始日期之åŽ"
- not_same_project: "ä¸å±žäºŽåŒä¸€ä¸ªé¡¹ç›®"
- circular_dependency: "æ¤å…³è”将导致循环ä¾èµ–"
- cant_link_an_issue_with_a_descendant: "问题ä¸èƒ½å…³è”到它的å任务"
-
- actionview_instancetag_blank_option: 请选择
-
- general_text_No: 'å¦'
- general_text_Yes: '是'
- general_text_no: 'å¦'
- general_text_yes: '是'
- general_lang_name: 'Simplified Chinese (ç®€ä½“ä¸æ–‡)'
- general_csv_separator: ','
- general_csv_decimal_separator: '.'
- general_csv_encoding: gb18030
- general_pdf_encoding: gb18030
- general_first_day_of_week: '7'
-
- notice_account_updated: å¸å·æ›´æ–°æˆåŠŸ
- notice_account_invalid_creditentials: æ— æ•ˆçš„ç”¨æˆ·åæˆ–密ç
- notice_account_password_updated: å¯†ç æ›´æ–°æˆåŠŸ
- notice_account_wrong_password: 密ç 错误
- notice_account_register_done: å¸å·åˆ›å»ºæˆåŠŸï¼Œè¯·ä½¿ç”¨æ³¨å†Œç¡®è®¤é‚®ä»¶ä¸çš„é“¾æŽ¥æ¥æ¿€æ´»æ‚¨çš„å¸å·ã€‚
- notice_account_unknown_email: 未知用户
- notice_can_t_change_password: 该å¸å·ä½¿ç”¨äº†å¤–部认è¯ï¼Œå› æ¤æ— 法更改密ç 。
- notice_account_lost_email_sent: 系统已将引导您设置新密ç 的邮件å‘é€ç»™æ‚¨ã€‚
- notice_account_activated: 您的å¸å·å·²è¢«æ¿€æ´»ã€‚您现在å¯ä»¥ç™»å½•了。
- notice_successful_create: 创建æˆåŠŸ
- notice_successful_update: æ›´æ–°æˆåŠŸ
- notice_successful_delete: åˆ é™¤æˆåŠŸ
- notice_successful_connection: 连接æˆåŠŸ
- notice_file_not_found: 您访问的页é¢ä¸å˜åœ¨æˆ–å·²è¢«åˆ é™¤ã€‚
- notice_locking_conflict: æ•°æ®å·²è¢«å¦ä¸€ä½ç”¨æˆ·æ›´æ–°
- notice_not_authorized: 对ä¸èµ·ï¼Œæ‚¨æ— æƒè®¿é—®æ¤é¡µé¢ã€‚
- notice_not_authorized_archived_project: è¦è®¿é—®çš„项目已ç»å½’档。
- notice_email_sent: "邮件已å‘é€è‡³ %{value}"
- notice_email_error: "å‘é€é‚®ä»¶æ—¶å‘生错误 (%{value})"
- notice_feeds_access_key_reseted: 您的RSSå˜å–键已被é‡ç½®ã€‚
- notice_api_access_key_reseted: 您的API访问键已被é‡ç½®ã€‚
- notice_failed_to_save_issues: "%{count} 个问题ä¿å˜å¤±è´¥ï¼ˆå…±é€‰æ‹© %{total} 个问题):%{ids}."
- notice_failed_to_save_members: "æˆå‘˜ä¿å˜å¤±è´¥: %{errors}."
- notice_no_issue_selected: "未选择任何问题ï¼è¯·é€‰æ‹©æ‚¨è¦ç¼–辑的问题。"
- notice_account_pending: "您的å¸å·å·²è¢«æˆåŠŸåˆ›å»ºï¼Œæ£åœ¨ç‰å¾…管ç†å‘˜çš„å®¡æ ¸ã€‚"
- notice_default_data_loaded: æˆåŠŸè½½å…¥é»˜è®¤è®¾ç½®ã€‚
- notice_unable_delete_version: æ— æ³•åˆ é™¤ç‰ˆæœ¬
- notice_unable_delete_time_entry: æ— æ³•åˆ é™¤å·¥æ—¶
- notice_issue_done_ratios_updated: 问题完æˆåº¦å·²æ›´æ–°ã€‚
- notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})"
-
- error_can_t_load_default_data: "æ— æ³•è½½å…¥é»˜è®¤è®¾ç½®ï¼š%{value}"
- error_scm_not_found: "版本库ä¸ä¸å˜åœ¨è¯¥æ¡ç›®å’Œï¼ˆæˆ–)其修订版本。"
- error_scm_command_failed: "访问版本库时å‘生错误:%{value}"
- error_scm_annotate: "该æ¡ç›®ä¸å˜åœ¨æˆ–æ— æ³•è¿½æº¯ã€‚"
- error_issue_not_found_in_project: '问题ä¸å˜åœ¨æˆ–ä¸å±žäºŽæ¤é¡¹ç›®'
- error_no_tracker_in_project: è¯¥é¡¹ç›®æœªè®¾å®šè·Ÿè¸ªæ ‡ç¾ï¼Œè¯·æ£€æŸ¥é¡¹ç›®é…置。
- error_no_default_issue_status: 未设置默认的问题状æ€ã€‚请检查系统设置("管ç†" -> "问题状æ€")。
- error_can_not_delete_custom_field: æ— æ³•åˆ é™¤è‡ªå®šä¹‰å±žæ€§
- error_can_not_delete_tracker: "è¯¥è·Ÿè¸ªæ ‡ç¾å·²åŒ…å«é—®é¢˜,æ— æ³•åˆ é™¤"
- error_can_not_remove_role: "该角色æ£åœ¨ä½¿ç”¨ä¸ï¼Œæ— æ³•åˆ é™¤"
- error_can_not_reopen_issue_on_closed_version: 该问题被关è”到一个已ç»å…³é—çš„ç‰ˆæœ¬ï¼Œå› æ¤æ— æ³•é‡æ–°æ‰“开。
- error_can_not_archive_project: è¯¥é¡¹ç›®æ— æ³•è¢«å˜æ¡£
- error_issue_done_ratios_not_updated: 问题完æˆåº¦æœªèƒ½è¢«æ›´æ–°ã€‚
- error_workflow_copy_source: 请选择一个æºè·Ÿè¸ªæ ‡ç¾æˆ–者角色
- error_workflow_copy_target: è¯·é€‰æ‹©ç›®æ ‡è·Ÿè¸ªæ ‡ç¾å’Œè§’色
- error_unable_delete_issue_status: 'æ— æ³•åˆ é™¤é—®é¢˜çŠ¶æ€'
- error_unable_to_connect: "æ— æ³•è¿žæŽ¥ (%{value})"
- warning_attachments_not_saved: "%{count} 个文件ä¿å˜å¤±è´¥"
-
- mail_subject_lost_password: "您的 %{value} 密ç "
- mail_body_lost_password: '请点击以下链接æ¥ä¿®æ”¹æ‚¨çš„密ç :'
- mail_subject_register: "%{value}å¸å·æ¿€æ´»"
- mail_body_register: 'è¯·ç‚¹å‡»ä»¥ä¸‹é“¾æŽ¥æ¥æ¿€æ´»æ‚¨çš„å¸å·ï¼š'
- mail_body_account_information_external: "您å¯ä»¥ä½¿ç”¨æ‚¨çš„ %{value} å¸å·æ¥ç™»å½•。"
- mail_body_account_information: 您的å¸å·ä¿¡æ¯
- mail_subject_account_activation_request: "%{value}å¸å·æ¿€æ´»è¯·æ±‚"
- mail_body_account_activation_request: "新用户(%{value}ï¼‰å·²å®Œæˆæ³¨å†Œï¼Œæ£åœ¨ç‰å€™æ‚¨çš„å®¡æ ¸ï¼š"
- mail_subject_reminder: "%{count} 个问题需è¦å°½å¿«è§£å†³ (%{days})"
- mail_body_reminder: "指派给您的 %{count} 个问题需è¦åœ¨ %{days} 天内完æˆï¼š"
- mail_subject_wiki_content_added: "'%{id}' wiki页é¢å·²æ·»åŠ "
- mail_body_wiki_content_added: "'%{id}' wiki页é¢å·²ç”± %{author} æ·»åŠ ã€‚"
- mail_subject_wiki_content_updated: "'%{id}' wiki页é¢å·²æ›´æ–°ã€‚"
- mail_body_wiki_content_updated: "'%{id}' wiki页é¢å·²ç”± %{author} 更新。"
-
- gui_validation_error: 1 个错误
- gui_validation_error_plural: "%{count} 个错误"
-
- field_name: åç§°
- field_description: æè¿°
- field_summary: 摘è¦
- field_is_required: å¿…å¡«
- field_firstname: åå—
- field_lastname: å§“æ°
- field_mail: 邮件地å€
- field_filename: 文件
- field_filesize: 大å°
- field_downloads: 下载次数
- field_author: 作者
- field_created_on: 创建于
- field_updated_on: 更新于
- field_field_format: æ ¼å¼
- field_is_for_all: 用于所有项目
- field_possible_values: å¯èƒ½çš„值
- field_regexp: æ£åˆ™è¡¨è¾¾å¼
- field_min_length: 最å°é•¿åº¦
- field_max_length: 最大长度
- field_value: 值
- field_category: 类别
- field_title: æ ‡é¢˜
- field_project: 项目
- field_issue: 问题
- field_status: 状æ€
- field_notes: 说明
- field_is_closed: 已关é—的问题
- field_is_default: 默认值
- field_tracker: 跟踪
- field_subject: 主题
- field_due_date: è®¡åˆ’å®Œæˆæ—¥æœŸ
- field_assigned_to: 指派给
- field_priority: 优先级
- field_fixed_version: ç›®æ ‡ç‰ˆæœ¬
- field_user: 用户
- field_principal: 用户/用户组
- field_role: 角色
- field_homepage: 主页
- field_is_public: 公开
- field_parent: 上级项目
- field_is_in_roadmap: åœ¨è·¯çº¿å›¾ä¸æ˜¾ç¤º
- field_login: 登录å
- field_mail_notification: 邮件通知
- field_admin: 管ç†å‘˜
- field_last_login_on: 最åŽç™»å½•
- field_language: è¯è¨€
- field_effective_date: 日期
- field_password: 密ç
- field_new_password: 新密ç
- field_password_confirmation: 确认
- field_version: 版本
- field_type: 类型
- field_host: 主机
- field_port: 端å£
- field_account: å¸å·
- field_base_dn: Base DN
- field_attr_login: 登录å属性
- field_attr_firstname: åå—属性
- field_attr_lastname: å§“æ°å±žæ€§
- field_attr_mail: 邮件属性
- field_onthefly: 峿—¶ç”¨æˆ·ç”Ÿæˆ
- field_start_date: 开始日期
- field_done_ratio: "% 完æˆ"
- field_auth_source: è®¤è¯æ¨¡å¼
- field_hide_mail: éšè—我的邮件地å€
- field_comments: 注释
- field_url: URL
- field_start_page: 起始页
- field_subproject: å项目
- field_hours: å°æ—¶
- field_activity: 活动
- field_spent_on: 日期
- field_identifier: æ ‡è¯†
- field_is_filter: 作为过滤æ¡ä»¶
- field_issue_to: 相关问题
- field_delay: 延期
- field_assignable: é—®é¢˜å¯æŒ‡æ´¾ç»™æ¤è§’色
- field_redirect_existing_links: é‡å®šå‘到现有链接
- field_estimated_hours: 预期时间
- field_column_names: 列
- field_time_entries: 工时
- field_time_zone: 时区
- field_searchable: å¯ç”¨ä½œæœç´¢æ¡ä»¶
- field_default_value: 默认值
- field_comments_sorting: 显示注释
- field_parent_title: 上级页é¢
- field_editable: å¯ç¼–辑
- field_watcher: 跟踪者
- field_identity_url: OpenID URL
- field_content: 内容
- field_group_by: æ ¹æ®æ¤æ¡ä»¶åˆ†ç»„
- field_sharing: 共享
- field_parent_issue: 父任务
- field_member_of_group: 用户组的æˆå‘˜
- field_assigned_to_role: 角色的æˆå‘˜
- field_text: æ–‡æœ¬å—æ®µ
- field_visible: å¯è§çš„
-
- setting_app_title: åº”ç”¨ç¨‹åºæ ‡é¢˜
- setting_app_subtitle: 应用程åºåæ ‡é¢˜
- setting_welcome_text: 欢迎文å—
- setting_default_language: 默认è¯è¨€
- setting_login_required: è¦æ±‚认è¯
- setting_self_registration: å…许自注册
- setting_attachment_max_size: 附件大å°é™åˆ¶
- setting_issues_export_limit: 问题导出æ¡ç›®çš„é™åˆ¶
- setting_mail_from: 邮件å‘件人地å€
- setting_bcc_recipients: ä½¿ç”¨å¯†ä»¶æŠ„é€ (bcc)
- setting_plain_text_mail: çº¯æ–‡æœ¬ï¼ˆæ— HTML)
- setting_host_name: 主机åç§°
- setting_text_formatting: æ–‡æœ¬æ ¼å¼
- setting_wiki_compression: 压缩WikiåŽ†å²æ–‡æ¡£
- setting_feeds_limit: RSS Feedå†…å®¹æ¡æ•°é™åˆ¶
- setting_default_projects_public: 新建项目默认为公开项目
- setting_autofetch_changesets: 自动获å–程åºå˜æ›´
- setting_sys_api_enabled: å¯ç”¨ç”¨äºŽç‰ˆæœ¬åº“管ç†çš„Web Service
- setting_commit_ref_keywords: 用于引用问题的关键å—
- setting_commit_fix_keywords: 用于解决问题的关键å—
- setting_autologin: 自动登录
- setting_date_format: æ—¥æœŸæ ¼å¼
- setting_time_format: æ—¶é—´æ ¼å¼
- setting_cross_project_issue_relations: å…许ä¸åŒé¡¹ç›®ä¹‹é—´çš„问题关è”
- setting_issue_list_default_columns: é—®é¢˜åˆ—è¡¨ä¸æ˜¾ç¤ºçš„默认列
- setting_emails_header: 邮件头
- setting_emails_footer: 邮件ç¾å
- setting_protocol: åè®®
- setting_per_page_options: æ¯é¡µæ˜¾ç¤ºæ¡ç›®ä¸ªæ•°çš„设置
- setting_user_format: ç”¨æˆ·æ˜¾ç¤ºæ ¼å¼
- setting_activity_days_default: åœ¨é¡¹ç›®æ´»åŠ¨ä¸æ˜¾ç¤ºçš„天数
- setting_display_subprojects_issues: 在项目页é¢ä¸Šé»˜è®¤æ˜¾ç¤ºå项目的问题
- setting_enabled_scm: å¯ç”¨ SCM
- setting_mail_handler_body_delimiters: åœ¨è¿™äº›è¡Œä¹‹åŽæˆªæ–邮件
- setting_mail_handler_api_enabled: å¯ç”¨ç”¨äºŽæŽ¥æ”¶é‚®ä»¶çš„æœåŠ¡
- setting_mail_handler_api_key: API key
- setting_sequential_project_identifiers: 顺åºäº§ç”Ÿé¡¹ç›®æ ‡è¯†
- setting_gravatar_enabled: 使用Gravatar用户头åƒ
- setting_gravatar_default: 默认的Gravatar头åƒ
- setting_diff_max_lines_displayed: 查看差别页é¢ä¸Šæ˜¾ç¤ºçš„æœ€å¤§è¡Œæ•°
- setting_file_max_size_displayed: å…许直接显示的最大文本文件
- setting_repository_log_display_limit: åœ¨æ–‡ä»¶å˜æ›´è®°å½•页é¢ä¸Šæ˜¾ç¤ºçš„æœ€å¤§ä¿®è®¢ç‰ˆæœ¬æ•°é‡
- setting_openid: å…许使用OpenID登录和注册
- setting_password_min_length: 最çŸå¯†ç 长度
- setting_new_project_user_role_id: éžç®¡ç†å‘˜ç”¨æˆ·æ–°å»ºé¡¹ç›®æ—¶å°†è¢«èµ‹äºˆçš„(在该项目ä¸çš„)角色
- setting_default_projects_modules: 新建项目默认å¯ç”¨çš„æ¨¡å—
- setting_issue_done_ratio: 计算问题完æˆåº¦ï¼š
- setting_issue_done_ratio_issue_field: 使用问题(的完æˆåº¦ï¼‰å±žæ€§
- setting_issue_done_ratio_issue_status: 使用问题状æ€
- setting_start_of_week: 日历开始于
- setting_rest_api_enabled: å¯ç”¨REST web service
- setting_cache_formatted_text: ç¼“å˜æ ¼å¼åŒ–æ–‡å—
- setting_default_notification_option: 默认æé†’选项
- setting_commit_logtime_enabled: 激活时间日志
- setting_commit_logtime_activity_id: 记录的活动
- setting_gantt_items_limit: 在甘特图上显示的最大记录数
-
- permission_add_project: 新建项目
- permission_add_subprojects: 新建å项目
- permission_edit_project: 编辑项目
- permission_select_project_modules: 选择项目模å—
- permission_manage_members: ç®¡ç†æˆå‘˜
- permission_manage_project_activities: 管ç†é¡¹ç›®æ´»åЍ
- permission_manage_versions: 管ç†ç‰ˆæœ¬
- permission_manage_categories: 管ç†é—®é¢˜ç±»åˆ«
- permission_view_issues: 查看问题
- permission_add_issues: 新建问题
- permission_edit_issues: 更新问题
- permission_manage_issue_relations: 管ç†é—®é¢˜å…³è”
- permission_add_issue_notes: æ·»åŠ è¯´æ˜Ž
- permission_edit_issue_notes: 编辑说明
- permission_edit_own_issue_notes: 编辑自己的说明
- permission_move_issues: 移动问题
- permission_delete_issues: åˆ é™¤é—®é¢˜
- permission_manage_public_queries: 管ç†å…¬å¼€çš„æŸ¥è¯¢
- permission_save_queries: ä¿å˜æŸ¥è¯¢
- permission_view_gantt: 查看甘特图
- permission_view_calendar: 查看日历
- permission_view_issue_watchers: 查看跟踪者列表
- permission_add_issue_watchers: æ·»åŠ è·Ÿè¸ªè€…
- permission_delete_issue_watchers: åˆ é™¤è·Ÿè¸ªè€…
- permission_log_time: 登记工时
- permission_view_time_entries: 查看耗时
- permission_edit_time_entries: 编辑耗时
- permission_edit_own_time_entries: 编辑自己的耗时
- permission_manage_news: ç®¡ç†æ–°é—»
- permission_comment_news: ä¸ºæ–°é—»æ·»åŠ è¯„è®º
- permission_manage_documents: ç®¡ç†æ–‡æ¡£
- permission_view_documents: 查看文档
- permission_manage_files: ç®¡ç†æ–‡ä»¶
- permission_view_files: 查看文件
- permission_manage_wiki: 管ç†Wiki
- permission_rename_wiki_pages: é‡å®šå‘/é‡å‘½åWiki页é¢
- permission_delete_wiki_pages: åˆ é™¤Wiki页é¢
- permission_view_wiki_pages: 查看Wiki
- permission_view_wiki_edits: 查看Wiki历å²è®°å½•
- permission_edit_wiki_pages: 编辑Wiki页é¢
- permission_delete_wiki_pages_attachments: åˆ é™¤é™„ä»¶
- permission_protect_wiki_pages: ä¿æŠ¤Wiki页é¢
- permission_manage_repository: 管ç†ç‰ˆæœ¬åº“
- permission_browse_repository: æµè§ˆç‰ˆæœ¬åº“
- permission_view_changesets: æŸ¥çœ‹å˜æ›´
- permission_commit_access: 访问æäº¤ä¿¡æ¯
- permission_manage_boards: 管ç†è®¨è®ºåŒº
- permission_view_messages: 查看帖å
- permission_add_messages: å‘表帖å
- permission_edit_messages: 编辑帖å
- permission_edit_own_messages: 编辑自己的帖å
- permission_delete_messages: åˆ é™¤å¸–å
- permission_delete_own_messages: åˆ é™¤è‡ªå·±çš„å¸–å
- permission_export_wiki_pages: 导出 wiki 页é¢
- permission_manage_subtasks: 管ç†å任务
-
- project_module_issue_tracking: 问题跟踪
- project_module_time_tracking: 时间跟踪
- project_module_news: æ–°é—»
- project_module_documents: 文档
- project_module_files: 文件
- project_module_wiki: Wiki
- project_module_repository: 版本库
- project_module_boards: 讨论区
- project_module_calendar: 日历
- project_module_gantt: 甘特图
-
- label_user: 用户
- label_user_plural: 用户
- label_user_new: 新建用户
- label_user_anonymous: 匿å用户
- label_project: 项目
- label_project_new: 新建项目
- label_project_plural: 项目
- label_x_projects:
- zero: æ— é¡¹ç›®
- one: 1 个项目
- other: "%{count} 个项目"
- label_project_all: 所有的项目
- label_project_latest: 最近的项目
- label_issue: 问题
- label_issue_new: 新建问题
- label_issue_plural: 问题
- label_issue_view_all: 查看所有问题
- label_issues_by: "按 %{value} 分组显示问题"
- label_issue_added: 问题已添åŠ
- label_issue_updated: 问题已更新
- label_document: 文档
- label_document_new: 新建文档
- label_document_plural: 文档
- label_document_added: 文档已添åŠ
- label_role: 角色
- label_role_plural: 角色
- label_role_new: 新建角色
- label_role_and_permissions: 角色和æƒé™
- label_member: æˆå‘˜
- label_member_new: 新建æˆå‘˜
- label_member_plural: æˆå‘˜
- label_tracker: è·Ÿè¸ªæ ‡ç¾
- label_tracker_plural: è·Ÿè¸ªæ ‡ç¾
- label_tracker_new: æ–°å»ºè·Ÿè¸ªæ ‡ç¾
- label_workflow: 工作æµç¨‹
- label_issue_status: 问题状æ€
- label_issue_status_plural: 问题状æ€
- label_issue_status_new: 新建问题状æ€
- label_issue_category: 问题类别
- label_issue_category_plural: 问题类别
- label_issue_category_new: 新建问题类别
- label_custom_field: 自定义属性
- label_custom_field_plural: 自定义属性
- label_custom_field_new: 新建自定义属性
- label_enumerations: 枚举值
- label_enumeration_new: 新建枚举值
- label_information: ä¿¡æ¯
- label_information_plural: ä¿¡æ¯
- label_please_login: 请登录
- label_register: 注册
- label_login_with_open_id_option: 或使用OpenID登录
- label_password_lost: 忘记密ç
- label_home: 主页
- label_my_page: 我的工作å°
- label_my_account: 我的å¸å·
- label_my_projects: 我的项目
- label_my_page_block: æˆ‘çš„å·¥ä½œå°æ¨¡å—
- label_administration: 管ç†
- label_login: 登录
- label_logout: 退出
- label_help: 帮助
- label_reported_issues: 已报告的问题
- label_assigned_to_me_issues: 指派给我的问题
- label_last_login: 最åŽç™»å½•
- label_registered_on: 注册于
- label_activity: 活动
- label_overall_activity: 活动概览
- label_user_activity: "%{value} 的活动"
- label_new: 新建
- label_logged_as: 登录为
- label_environment: 环境
- label_authentication: 认è¯
- label_auth_source: è®¤è¯æ¨¡å¼
- label_auth_source_new: æ–°å»ºè®¤è¯æ¨¡å¼
- label_auth_source_plural: è®¤è¯æ¨¡å¼
- label_subproject_plural: å项目
- label_subproject_new: 新建å项目
- label_and_its_subprojects: "%{value} åŠå…¶å项目"
- label_min_max_length: æœ€å° - 最大 长度
- label_list: 列表
- label_date: 日期
- label_integer: æ•´æ•°
- label_float: 浮点数
- label_boolean: 布尔值
- label_string: å—符串
- label_text: 文本
- label_attribute: 属性
- label_attribute_plural: 属性
- label_download: "%{count} 次下载"
- label_download_plural: "%{count} 次下载"
- label_no_data: 没有任何数æ®å¯ä¾›æ˜¾ç¤º
- label_change_status: å˜æ›´çжæ€
- label_history: 历å²è®°å½•
- label_attachment: 文件
- label_attachment_new: 新建文件
- label_attachment_delete: åˆ é™¤æ–‡ä»¶
- label_attachment_plural: 文件
- label_file_added: 文件已添åŠ
- label_report: 报表
- label_report_plural: 报表
- label_news: æ–°é—»
- label_news_new: æ·»åŠ æ–°é—»
- label_news_plural: æ–°é—»
- label_news_latest: 最近的新闻
- label_news_view_all: 查看所有新闻
- label_news_added: 新闻已添åŠ
- label_settings: é…ç½®
- label_overview: 概述
- label_version: 版本
- label_version_new: 新建版本
- label_version_plural: 版本
- label_close_versions: å…³é—已完æˆçš„版本
- label_confirmation: 确认
- label_export_to: 导出
- label_read: 读å–...
- label_public_projects: 公开的项目
- label_open_issues: 打开
- label_open_issues_plural: 打开
- label_closed_issues: 已关é—
- label_closed_issues_plural: 已关é—
- label_x_open_issues_abbr_on_total:
- zero: 0 打开 / %{total}
- one: 1 打开 / %{total}
- other: "%{count} 打开 / %{total}"
- label_x_open_issues_abbr:
- zero: 0 打开
- one: 1 打开
- other: "%{count} 打开"
- label_x_closed_issues_abbr:
- zero: 0 已关é—
- one: 1 已关é—
- other: "%{count} 已关é—"
- label_total: åˆè®¡
- label_permissions: æƒé™
- label_current_status: 当å‰çжæ€
- label_new_statuses_allowed: å…许的新状æ€
- label_all: 全部
- label_none: æ—
- label_nobody: æ— äºº
- label_next: 下一页
- label_previous: 上一页
- label_used_by: 使用ä¸
- label_details: 详情
- label_add_note: æ·»åŠ è¯´æ˜Ž
- label_per_page: æ¯é¡µ
- label_calendar: 日历
- label_months_from: 个月以æ¥
- label_gantt: 甘特图
- label_internal: 内部
- label_last_changes: "最近的 %{count} æ¬¡å˜æ›´"
- label_change_view_all: æŸ¥çœ‹æ‰€æœ‰å˜æ›´
- label_personalize_page: 个性化定制本页
- label_comment: 评论
- label_comment_plural: 评论
- label_x_comments:
- zero: æ— è¯„è®º
- one: 1 æ¡è¯„论
- other: "%{count} æ¡è¯„论"
- label_comment_add: æ·»åŠ è¯„è®º
- label_comment_added: 评论已添åŠ
- label_comment_delete: åˆ é™¤è¯„è®º
- label_query: 自定义查询
- label_query_plural: 自定义查询
- label_query_new: 新建查询
- label_filter_add: å¢žåŠ è¿‡æ»¤å™¨
- label_filter_plural: 过滤器
- label_equals: ç‰äºŽ
- label_not_equals: ä¸ç‰äºŽ
- label_in_less_than: 剩余天数å°äºŽ
- label_in_more_than: 剩余天数大于
- label_greater_or_equal: '>='
- label_less_or_equal: '<='
- label_in: 剩余天数
- label_today: 今天
- label_all_time: 全部时间
- label_yesterday: 昨天
- label_this_week: 本周
- label_last_week: 上周
- label_last_n_days: "æœ€åŽ %{count} 天"
- label_this_month: 本月
- label_last_month: 上月
- label_this_year: 今年
- label_date_range: 日期范围
- label_less_than_ago: 之å‰å¤©æ•°å°‘于
- label_more_than_ago: 之å‰å¤©æ•°å¤§äºŽ
- label_ago: 之å‰å¤©æ•°
- label_contains: 包å«
- label_not_contains: ä¸åŒ…å«
- label_day_plural: 天
- label_repository: 版本库
- label_repository_plural: 版本库
- label_browse: æµè§ˆ
- label_modification: "%{count} 个更新"
- label_modification_plural: "%{count} 个更新"
- label_branch: 分支
- label_tag: æ ‡ç¾
- label_revision: 修订
- label_revision_plural: 修订
- label_revision_id: 修订 %{value}
- label_associated_revisions: 相关修订版本
- label_added: 已添åŠ
- label_modified: 已修改
- label_copied: å·²å¤åˆ¶
- label_renamed: å·²é‡å‘½å
- label_deleted: å·²åˆ é™¤
- label_latest_revision: 最近的修订版本
- label_latest_revision_plural: 最近的修订版本
- label_view_revisions: 查看修订
- label_view_all_revisions: 查看所有修订
- label_max_size: 最大尺寸
- label_sort_highest: 置顶
- label_sort_higher: 上移
- label_sort_lower: 下移
- label_sort_lowest: 置底
- label_roadmap: 路线图
- label_roadmap_due_in: "æˆªæ¢æ—¥æœŸåˆ° %{value}"
- label_roadmap_overdue: "%{value} 延期"
- label_roadmap_no_issues: 该版本没有问题
- label_search: æœç´¢
- label_result_plural: 结果
- label_all_words: 所有å•è¯
- label_wiki: Wiki
- label_wiki_edit: Wiki 编辑
- label_wiki_edit_plural: Wiki 编辑记录
- label_wiki_page: Wiki 页é¢
- label_wiki_page_plural: Wiki 页é¢
- label_index_by_title: æŒ‰æ ‡é¢˜ç´¢å¼•
- label_index_by_date: 按日期索引
- label_current_version: 当å‰ç‰ˆæœ¬
- label_preview: 预览
- label_feed_plural: Feeds
- label_changes_details: æ‰€æœ‰å˜æ›´çš„详情
- label_issue_tracking: 问题跟踪
- label_spent_time: 耗时
- label_overall_spent_time: 总体耗时
- label_f_hour: "%{value} å°æ—¶"
- label_f_hour_plural: "%{value} å°æ—¶"
- label_time_tracking: 时间跟踪
- label_change_plural: å˜æ›´
- label_statistics: 统计
- label_commits_per_month: æ¯æœˆæäº¤æ¬¡æ•°
- label_commits_per_author: æ¯ç”¨æˆ·æäº¤æ¬¡æ•°
- label_view_diff: 查看差别
- label_diff_inline: 直列
- label_diff_side_by_side: 并排
- label_options: 选项
- label_copy_workflow_from: 从以下选项å¤åˆ¶å·¥ä½œæµç¨‹
- label_permissions_report: æƒé™æŠ¥è¡¨
- label_watched_issues: 跟踪的问题
- label_related_issues: 相关的问题
- label_applied_status: 应用åŽçš„状æ€
- label_loading: 载入ä¸...
- label_relation_new: 新建关è”
- label_relation_delete: åˆ é™¤å…³è”
- label_relates_to: å…³è”到
- label_duplicates: é‡å¤
- label_duplicated_by: 与其é‡å¤
- label_blocks: 阻挡
- label_blocked_by: 被阻挡
- label_precedes: 优先于
- label_follows: è·ŸéšäºŽ
- label_end_to_start: 结æŸ-开始
- label_end_to_end: 结æŸ-结æŸ
- label_start_to_start: 开始-开始
- label_start_to_end: 开始-结æŸ
- label_stay_logged_in: ä¿æŒç™»å½•状æ€
- label_disabled: ç¦ç”¨
- label_show_completed_versions: 显示已完æˆçš„版本
- label_me: 我
- label_board: 讨论区
- label_board_new: 新建讨论区
- label_board_plural: 讨论区
- label_board_locked: é”定
- label_board_sticky: 置顶
- label_topic_plural: 主题
- label_message_plural: 帖å
- label_message_last: 最新的帖å
- label_message_new: æ–°è´´
- label_message_posted: å‘帖æˆåŠŸ
- label_reply_plural: 回å¤
- label_send_information: 给用户å‘é€å¸å·ä¿¡æ¯
- label_year: å¹´
- label_month: 月
- label_week: 周
- label_date_from: 从
- label_date_to: 到
- label_language_based: æ ¹æ®ç”¨æˆ·çš„è¯è¨€
- label_sort_by: "æ ¹æ® %{value} 排åº"
- label_send_test_email: å‘逿µ‹è¯•邮件
- label_feeds_access_key: RSSå˜å–é”®
- label_missing_feeds_access_key: 缺少RSSå˜å–é”®
- label_feeds_access_key_created_on: "RSSå˜å–键是在 %{value} 之å‰å»ºç«‹çš„"
- label_module_plural: 模å—
- label_added_time_by: "ç”± %{author} 在 %{age} 之剿·»åŠ "
- label_updated_time: " 更新于 %{value} 之å‰"
- label_updated_time_by: "ç”± %{author} 更新于 %{age} 之å‰"
- label_jump_to_a_project: 选择一个项目...
- label_file_plural: 文件
- label_changeset_plural: å˜æ›´
- label_default_columns: 默认列
- label_no_change_option: (ä¸å˜)
- label_bulk_edit_selected_issues: 批é‡ä¿®æ”¹é€‰ä¸çš„问题
- label_theme: 主题
- label_default: 默认
- label_search_titles_only: ä»…åœ¨æ ‡é¢˜ä¸æœç´¢
- label_user_mail_option_all: "æ”¶å–æˆ‘的项目的所有通知"
- label_user_mail_option_selected: "æ”¶å–选ä¸é¡¹ç›®çš„æ‰€æœ‰é€šçŸ¥..."
- label_user_mail_option_none: "䏿”¶å–任何通知"
- label_user_mail_option_only_my_events: "åªæ”¶å–我跟踪或å‚与的项目的通知"
- label_user_mail_option_only_assigned: "åªæ”¶å–分é…给我的"
- label_user_mail_option_only_owner: åªæ”¶å–由我创建的
- label_user_mail_no_self_notified: "ä¸è¦å‘é€å¯¹æˆ‘自己æäº¤çš„修改的通知"
- label_registration_activation_by_email: é€šè¿‡é‚®ä»¶è®¤è¯æ¿€æ´»å¸å·
- label_registration_manual_activation: 手动激活å¸å·
- label_registration_automatic_activation: 自动激活å¸å·
- label_display_per_page: "æ¯é¡µæ˜¾ç¤ºï¼š%{value}"
- label_age: æäº¤æ—¶é—´
- label_change_properties: 修改属性
- label_general: 一般
- label_more: 更多
- label_scm: SCM
- label_plugins: æ’ä»¶
- label_ldap_authentication: LDAP 认è¯
- label_downloads_abbr: D/L
- label_optional_description: å¯é€‰çš„æè¿°
- label_add_another_file: æ·»åŠ å…¶å®ƒæ–‡ä»¶
- label_preferences: 首选项
- label_chronological_order: 按时间顺åº
- label_reverse_chronological_order: 按时间顺åºï¼ˆå€’åºï¼‰
- label_planning: 计划
- label_incoming_emails: 接收邮件
- label_generate_key: 生æˆä¸€ä¸ªkey
- label_issue_watchers: 跟踪者
- label_example: 示例
- label_display: 显示
- label_sort: 排åº
- label_ascending: å‡åº
- label_descending: é™åº
- label_date_from_to: 从 %{start} 到 %{end}
- label_wiki_content_added: Wiki 页é¢å·²æ·»åŠ
- label_wiki_content_updated: Wiki 页é¢å·²æ›´æ–°
- label_group: 组
- label_group_plural: 组
- label_group_new: 新建组
- label_time_entry_plural: 耗时
- label_version_sharing_none: ä¸å…±äº«
- label_version_sharing_descendants: 与å项目共享
- label_version_sharing_hierarchy: 与项目继承层次共享
- label_version_sharing_tree: ä¸Žé¡¹ç›®æ ‘å…±äº«
- label_version_sharing_system: 与所有项目共享
- label_update_issue_done_ratios: 更新问题的完æˆåº¦
- label_copy_source: æº
- label_copy_target: ç›®æ ‡
- label_copy_same_as_target: ä¸Žç›®æ ‡ä¸€è‡´
- label_display_used_statuses_only: åªæ˜¾ç¤ºè¢«æ¤è·Ÿè¸ªæ ‡ç¾ä½¿ç”¨çš„状æ€
- label_api_access_key: API访问键
- label_missing_api_access_key: 缺少API访问键
- label_api_access_key_created_on: API访问键是在 %{value} 之å‰å»ºç«‹çš„
- label_profile: 简介
- label_subtask_plural: å任务
- label_project_copy_notifications: å¤åˆ¶é¡¹ç›®æ—¶å‘é€é‚®ä»¶é€šçŸ¥
- label_principal_search: "æœç´¢ç”¨æˆ·æˆ–组:"
- label_user_search: "æœç´¢ç”¨æˆ·ï¼š"
-
- button_login: 登录
- button_submit: æäº¤
- button_save: ä¿å˜
- button_check_all: 全选
- button_uncheck_all: 清除
- button_delete: åˆ é™¤
- button_create: 创建
- button_create_and_continue: 创建并继ç»
- button_test: 测试
- button_edit: 编辑
- button_edit_associated_wikipage: "编辑相关wiki页é¢: %{page_title}"
- button_add: 新增
- button_change: 修改
- button_apply: 应用
- button_clear: 清除
- button_lock: é”定
- button_unlock: è§£é”
- button_download: 下载
- button_list: 列表
- button_view: 查看
- button_move: 移动
- button_move_and_follow: 移动并转到新问题
- button_back: 返回
- button_cancel: å–æ¶ˆ
- button_activate: 激活
- button_sort: 排åº
- button_log_time: 登记工时
- button_rollback: æ¢å¤åˆ°è¿™ä¸ªç‰ˆæœ¬
- button_watch: 跟踪
- button_unwatch: å–æ¶ˆè·Ÿè¸ª
- button_reply: 回å¤
- button_archive: å˜æ¡£
- button_unarchive: å–æ¶ˆå˜æ¡£
- button_reset: é‡ç½®
- button_rename: é‡å‘½å/é‡å®šå‘
- button_change_password: 修改密ç
- button_copy: å¤åˆ¶
- button_copy_and_follow: å¤åˆ¶å¹¶è½¬åˆ°æ–°é—®é¢˜
- button_annotate: 追溯
- button_update: æ›´æ–°
- button_configure: é…ç½®
- button_quote: 引用
- button_duplicate: 副本
- button_show: 显示
-
- status_active: 活动的
- status_registered: 已注册
- status_locked: å·²é”定
-
- version_status_open: 打开
- version_status_locked: é”定
- version_status_closed: å…³é—
-
- field_active: 活动
-
- text_select_mail_notifications: 选择需è¦å‘é€é‚®ä»¶é€šçŸ¥çš„动作
- text_regexp_info: 例如:^[A-Z0-9]+$
- text_min_max_length_info: 0 表示没有é™åˆ¶
- text_project_destroy_confirmation: 您确信è¦åˆ é™¤è¿™ä¸ªé¡¹ç›®ä»¥åŠæ‰€æœ‰ç›¸å…³çš„æ•°æ®å—?
- text_subprojects_destroy_warning: "以下åé¡¹ç›®ä¹Ÿå°†è¢«åŒæ—¶åˆ 除:%{value}"
- text_workflow_edit: é€‰æ‹©è§’è‰²å’Œè·Ÿè¸ªæ ‡ç¾æ¥ç¼–辑工作æµç¨‹
- text_are_you_sure: 您确定?
- text_are_you_sure_with_children: "åˆ é™¤é—®é¢˜åŠå任务?"
- text_journal_changed: "%{label} 从 %{old} å˜æ›´ä¸º %{new}"
- text_journal_set_to: "%{label} 被设置为 %{value}"
- text_journal_deleted: "%{label} å·²åˆ é™¤ (%{old})"
- text_journal_added: "%{label} %{value} å·²æ·»åŠ "
- text_tip_issue_begin_day: 今天开始的任务
- text_tip_issue_end_day: 今天结æŸçš„任务
- text_tip_issue_begin_end_day: 今天开始并结æŸçš„任务
- text_project_identifier_info: 'åªå…许使用å°å†™å—æ¯ï¼ˆa-z),数å—和连å—符(-)。 请注æ„ï¼Œæ ‡è¯†ç¬¦ä¿å˜åŽå°†ä¸å¯ä¿®æ”¹ã€‚'
- text_caracters_maximum: "最多 %{count} 个å—符。"
- text_caracters_minimum: "è‡³å°‘éœ€è¦ %{count} 个å—符。"
- text_length_between: "长度必须在 %{min} 到 %{max} 个å—符之间。"
- text_tracker_no_workflow: æ¤è·Ÿè¸ªæ ‡ç¾æœªå®šä¹‰å·¥ä½œæµç¨‹
- text_unallowed_characters: éžæ³•å—符
- text_comma_separated: å¯ä»¥ä½¿ç”¨å¤šä¸ªå€¼ï¼ˆç”¨é€—å·,分开)。
- text_line_separated: å¯ä»¥ä½¿ç”¨å¤šä¸ªå€¼ï¼ˆæ¯è¡Œä¸€ä¸ªå€¼ï¼‰ã€‚
- text_issues_ref_in_commit_messages: 在æäº¤ä¿¡æ¯ä¸å¼•用和解决问题
- text_issue_added: "问题 %{id} 已由 %{author} æäº¤ã€‚"
- text_issue_updated: "问题 %{id} 已由 %{author} 更新。"
- text_wiki_destroy_confirmation: 您确定è¦åˆ 除这个 wiki åŠå…¶æ‰€æœ‰å†…容å—?
- text_issue_category_destroy_question: "有一些问题(%{count} 个)属于æ¤ç±»åˆ«ã€‚æ‚¨æƒ³è¿›è¡Œå“ªç§æ“作?"
- text_issue_category_destroy_assignments: åˆ é™¤é—®é¢˜çš„æ‰€å±žç±»åˆ«ï¼ˆé—®é¢˜å˜ä¸ºæ— 类别)
- text_issue_category_reassign_to: 为问题选择其它类别
- text_user_mail_option: "对于没有选ä¸çš„项目,您将åªä¼šæ”¶åˆ°æ‚¨è·Ÿè¸ªæˆ–å‚与的项目的通知(比如说,您是问题的报告者, 或被指派解决æ¤é—®é¢˜ï¼‰ã€‚"
- text_no_configuration_data: "角色ã€è·Ÿè¸ªæ ‡ç¾ã€é—®é¢˜çжæ€å’Œå·¥ä½œæµç¨‹è¿˜æ²¡æœ‰è®¾ç½®ã€‚\n强烈建议您先载入默认设置,然åŽåœ¨æ¤åŸºç¡€ä¸Šè¿›è¡Œä¿®æ”¹ã€‚"
- text_load_default_configuration: 载入默认设置
- text_status_changed_by_changeset: "å·²åº”ç”¨åˆ°å˜æ›´åˆ—表 %{value}."
- text_time_logged_by_changeset: "已应用到修订版本 %{value}."
- text_issues_destroy_confirmation: '您确定è¦åˆ 除选ä¸çš„问题å—?'
- text_select_project_modules: '请选择æ¤é¡¹ç›®å¯ä»¥ä½¿ç”¨çš„æ¨¡å—:'
- text_default_administrator_account_changed: 默认的管ç†å‘˜å¸å·å·²æ”¹å˜
- text_file_repository_writable: 附件路径å¯å†™
- text_plugin_assets_writable: æ’件的附件路径å¯å†™
- text_rmagick_available: RMagick å¯ç”¨ï¼ˆå¯é€‰çš„)
- text_destroy_time_entries_question: 您è¦åˆ 除的问题已ç»ä¸ŠæŠ¥äº† %{hours} å°æ—¶çš„工作é‡ã€‚æ‚¨æƒ³è¿›è¡Œé‚£ç§æ“作?
- text_destroy_time_entries: åˆ é™¤ä¸ŠæŠ¥çš„å·¥ä½œé‡
- text_assign_time_entries_to_project: å°†å·²ä¸ŠæŠ¥çš„å·¥ä½œé‡æäº¤åˆ°é¡¹ç›®ä¸
- text_reassign_time_entries: 'å°†å·²ä¸ŠæŠ¥çš„å·¥ä½œé‡æŒ‡å®šåˆ°æ¤é—®é¢˜ï¼š'
- text_user_wrote: "%{value} 写到:"
- text_enumeration_destroy_question: "%{count} 个对象被关è”到了这个枚举值。"
- text_enumeration_category_reassign_to: '将它们关è”到新的枚举值:'
- text_email_delivery_not_configured: "邮件傿•°å°šæœªé…ç½®ï¼Œå› æ¤é‚®ä»¶é€šçŸ¥åŠŸèƒ½å·²è¢«ç¦ç”¨ã€‚\n请在config/configuration.ymlä¸é…置您的SMTPæœåŠ¡å™¨ä¿¡æ¯å¹¶é‡æ–°å¯åŠ¨ä»¥ä½¿å…¶ç”Ÿæ•ˆã€‚"
- text_repository_usernames_mapping: "选择或更新与版本库ä¸çš„用户å对应的Redmine用户。\n版本库ä¸ä¸ŽRedmineä¸çš„åŒå用户将被自动对应。"
- text_diff_truncated: '... å·®åˆ«å†…å®¹è¶…è¿‡äº†å¯æ˜¾ç¤ºçš„æœ€å¤§è¡Œæ•°å¹¶å·²è¢«æˆªæ–'
- text_custom_field_possible_values_info: 'æ¯é¡¹æ•°å€¼ä¸€è¡Œ'
- text_wiki_page_destroy_question: æ¤é¡µé¢æœ‰ %{descendants} 个å页é¢å’Œä¸‹çº§é¡µé¢ã€‚æ‚¨æƒ³è¿›è¡Œé‚£ç§æ“作?
- text_wiki_page_nullify_children: å°†å页é¢ä¿ç•™ä¸ºæ ¹é¡µé¢
- text_wiki_page_destroy_children: åˆ é™¤å页é¢åŠå…¶æ‰€æœ‰ä¸‹çº§é¡µé¢
- text_wiki_page_reassign_children: å°†å页é¢çš„上级页é¢è®¾ç½®ä¸º
- text_own_membership_delete_confirmation: ä½ æ£åœ¨åˆ é™¤ä½ çŽ°æœ‰çš„æŸäº›æˆ–全部æƒé™ï¼Œå¦‚æžœè¿™æ ·åšäº†ä½ å¯èƒ½å°†ä¼šå†ä¹Ÿæ— æ³•ç¼–è¾‘è¯¥é¡¹ç›®äº†ã€‚ä½ ç¡®å®šè¦ç»§ç»å—?
- text_zoom_in: 放大
- text_zoom_out: 缩å°
-
- default_role_manager: 管ç†äººå‘˜
- default_role_developer: å¼€å‘人员
- default_role_reporter: 报告人员
- default_tracker_bug: 错误
- default_tracker_feature: 功能
- default_tracker_support: 支æŒ
- default_issue_status_new: 新建
- default_issue_status_in_progress: 进行ä¸
- default_issue_status_resolved: 已解决
- default_issue_status_feedback: å馈
- default_issue_status_closed: 已关é—
- default_issue_status_rejected: 已拒ç»
- default_doc_category_user: 用户文档
- default_doc_category_tech: 技术文档
- default_priority_low: 低
- default_priority_normal: 普通
- default_priority_high: 高
- default_priority_urgent: 紧急
- default_priority_immediate: 立刻
- default_activity_design: 设计
- default_activity_development: å¼€å‘
-
- enumeration_issue_priorities: 问题优先级
- enumeration_doc_categories: 文档类别
- enumeration_activities: 活动(时间跟踪)
- enumeration_system_activity: 系统活动
-
- field_warn_on_leaving_unsaved: 当离开未ä¿å˜å†…å®¹çš„é¡µé¢æ—¶ï¼Œæç¤ºæˆ‘
- text_warn_on_leaving_unsaved: 若离开当å‰é¡µé¢ï¼Œåˆ™è¯¥é¡µé¢å†…未ä¿å˜çš„内容将丢失。
- label_my_queries: 我的自定义查询
- text_journal_changed_no_detail: "%{label} 已更新。"
- label_news_comment_added: æ·»åŠ åˆ°æ–°é—»çš„è¯„è®º
- button_expand_all: 展开所有
- button_collapse_all: åˆæ‹¢æ‰€æœ‰
- label_additional_workflow_transitions_for_assignee: 当用户是问题的分é…对象时所å…许的问题状æ€è½¬æ¢
- label_additional_workflow_transitions_for_author: 当用户是问题作者时所å…许的问题状æ€è½¬æ¢
- label_bulk_edit_selected_time_entries: 批é‡ä¿®æ”¹é€‰å®šçš„æ—¶é—´æ¡ç›®
- text_time_entries_destroy_confirmation: 是å¦ç¡®å®šè¦åˆ 除选定的时间æ¡ç›®ï¼Ÿ
- label_role_anonymous: Anonymous
- label_role_non_member: Non member
- label_issue_note_added: 问题备注已添åŠ
- label_issue_status_updated: é—®é¢˜çŠ¶æ€æ›´æ–°
- label_issue_priority_updated: 问题优先级更新
- label_issues_visibility_own: 创建或分é…给用户的问题
- field_issues_visibility: 问题å¯è§
- label_issues_visibility_all: 全部问题
- permission_set_own_issues_private: è®¾ç½®è‡ªå·±çš„é—®é¢˜ä¸ºå…¬å¼€æˆ–ç§æœ‰
- field_is_private: ç§æœ‰
- permission_set_issues_private: è®¾ç½®é—®é¢˜ä¸ºå…¬å¼€æˆ–ç§æœ‰
- label_issues_visibility_public: 全部éžç§æœ‰é—®é¢˜
- text_issues_destroy_descendants_confirmation: æ¤æ“ä½œåŒæ—¶ä¼šåˆ 除 %{count} 个å任务。
-
- field_commit_logs_encoding: æäº¤æ³¨é‡Šçš„ç¼–ç
- field_scm_path_encoding: 路径编ç
- text_scm_path_encoding_note: "默认: UTF-8"
- field_path_to_repository: 库路径
- field_root_directory: æ ¹ç›®å½•
- field_cvs_module: CVS Module
- field_cvsroot: CVSROOT
- text_mercurial_repository_note: 本地库 (e.g. /hgrepo, c:\hgrepo)
- text_scm_command: 命令
- text_scm_command_version: 版本
- label_git_report_last_commit: 报告最åŽä¸€æ¬¡æ–‡ä»¶/目录æäº¤
- text_scm_config: 您å¯ä»¥åœ¨config/configuration.ymlä¸é…置您的SCM命令。 请在编辑åŽï¼Œé‡å¯Redmine应用。
- text_scm_command_not_available: Scm命令ä¸å¯ç”¨ã€‚ 请检查管ç†é¢æ¿çš„é…置。
- text_git_repository_note: åº“ä¸æ— 内容。(e.g. /gitrepo, c:\gitrepo)
- notice_issue_successful_create: 问题 %{id} 已创建。
- label_between: 介于
- setting_issue_group_assignment: å…许问题被分é…给组
- label_diff: diff
- description_query_sort_criteria_direction: æŽ’åºæ–¹å¼
- description_project_scope: æœç´¢èŒƒå›´
- description_filter: 过滤器
- description_user_mail_notification: 邮件通知设置
- description_date_from: 输入开始日期
- description_message_content: ä¿¡æ¯å†…容
- description_available_columns: 备选列
- description_date_range_interval: æŒ‰å¼€å§‹æ—¥æœŸå’Œç»“æŸæ—¥æœŸé€‰æ‹©èŒƒå›´
- description_issue_category_reassign: 选择问题类别
- description_search: æœç´¢å—段
- description_notes: 批注
- description_date_range_list: 从列表ä¸é€‰æ‹©èŒƒå›´
- description_choose_project: 项目
- description_date_to: è¾“å…¥ç»“æŸæ—¥æœŸ
- description_query_sort_criteria_attribute: æŽ’åºæ–¹å¼
- description_wiki_subpages_reassign: 选择父页é¢
- description_selected_columns: 已选列
- label_parent_revision: 父修订
- label_child_revision: å修订
- error_scm_annotate_big_text_file: è¾“å…¥æ–‡æœ¬å†…å®¹è¶…é•¿ï¼Œæ— æ³•è¾“å…¥ã€‚
- setting_default_issue_start_date_to_creation_date: ä½¿ç”¨å½“å‰æ—¥æœŸä½œä¸ºæ–°é—®é¢˜çš„开始日期
- button_edit_section: Edit this section
- setting_repositories_encodings: Attachments and repositories encodings
- description_all_columns: All Columns
- button_export: Export
- label_export_options: "%{export_format} export options"
- error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/54/547682ef5ea0e2a3da7440949449d21631f7fc4b.svn-base
--- a/.svn/pristine/54/547682ef5ea0e2a3da7440949449d21631f7fc4b.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require File.expand_path('../../test_helper', __FILE__)
-require 'trackers_controller'
-
-# Re-raise errors caught by the controller.
-class TrackersController; def rescue_action(e) raise e end; end
-
-class TrackersControllerTest < ActionController::TestCase
- fixtures :trackers, :projects, :projects_trackers, :users, :issues, :custom_fields
-
- def setup
- @controller = TrackersController.new
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
- User.current = nil
- @request.session[:user_id] = 1 # admin
- end
-
- def test_index
- get :index
- assert_response :success
- assert_template 'index'
- end
-
- def test_index_by_anonymous_should_redirect_to_login_form
- @request.session[:user_id] = nil
- get :index
- assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftrackers'
- end
-
- def test_index_by_user_should_respond_with_406
- @request.session[:user_id] = 2
- get :index
- assert_response 406
- end
-
- def test_new
- get :new
- assert_response :success
- assert_template 'new'
- end
-
- def test_create
- assert_difference 'Tracker.count' do
- post :create, :tracker => { :name => 'New tracker', :project_ids => ['1', '', ''], :custom_field_ids => ['1', '6', ''] }
- end
- assert_redirected_to :action => 'index'
- tracker = Tracker.first(:order => 'id DESC')
- assert_equal 'New tracker', tracker.name
- assert_equal [1], tracker.project_ids.sort
- assert_equal [1, 6], tracker.custom_field_ids
- assert_equal 0, tracker.workflows.count
- end
-
- def test_create_new_with_workflow_copy
- assert_difference 'Tracker.count' do
- post :create, :tracker => { :name => 'New tracker' }, :copy_workflow_from => 1
- end
- assert_redirected_to :action => 'index'
- tracker = Tracker.find_by_name('New tracker')
- assert_equal 0, tracker.projects.count
- assert_equal Tracker.find(1).workflows.count, tracker.workflows.count
- end
-
- def test_create_new_failure
- assert_no_difference 'Tracker.count' do
- post :create, :tracker => { :name => '', :project_ids => ['1', '', ''], :custom_field_ids => ['1', '6', ''] }
- end
- assert_response :success
- assert_template 'new'
- end
-
- def test_edit
- Tracker.find(1).project_ids = [1, 3]
-
- get :edit, :id => 1
- assert_response :success
- assert_template 'edit'
-
- assert_tag :input, :attributes => { :name => 'tracker[project_ids][]',
- :value => '1',
- :checked => 'checked' }
-
- assert_tag :input, :attributes => { :name => 'tracker[project_ids][]',
- :value => '2',
- :checked => nil }
-
- assert_tag :input, :attributes => { :name => 'tracker[project_ids][]',
- :value => '',
- :type => 'hidden'}
- end
-
- def test_update
- put :update, :id => 1, :tracker => { :name => 'Renamed',
- :project_ids => ['1', '2', ''] }
- assert_redirected_to :action => 'index'
- assert_equal [1, 2], Tracker.find(1).project_ids.sort
- end
-
- def test_update_without_projects
- put :update, :id => 1, :tracker => { :name => 'Renamed',
- :project_ids => [''] }
- assert_redirected_to :action => 'index'
- assert Tracker.find(1).project_ids.empty?
- end
-
- def test_move_lower
- tracker = Tracker.find_by_position(1)
- put :update, :id => 1, :tracker => { :move_to => 'lower' }
- assert_equal 2, tracker.reload.position
- end
-
- def test_destroy
- tracker = Tracker.create!(:name => 'Destroyable')
- assert_difference 'Tracker.count', -1 do
- delete :destroy, :id => tracker.id
- end
- assert_redirected_to :action => 'index'
- assert_nil flash[:error]
- end
-
- def test_destroy_tracker_in_use
- assert_no_difference 'Tracker.count' do
- delete :destroy, :id => 1
- end
- assert_redirected_to :action => 'index'
- assert_not_nil flash[:error]
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/55/559174dc6dc9fe3ee3e34f610d2f9ef569c9ebd8.svn-base
--- a/.svn/pristine/55/559174dc6dc9fe3ee3e34f610d2f9ef569c9ebd8.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,877 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require File.expand_path('../../test_helper', __FILE__)
-
-class UserTest < ActiveSupport::TestCase
- fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources,
- :trackers, :issue_statuses,
- :projects_trackers,
- :watchers,
- :issue_categories, :enumerations, :issues,
- :journals, :journal_details,
- :groups_users,
- :enabled_modules,
- :workflows
-
- def setup
- @admin = User.find(1)
- @jsmith = User.find(2)
- @dlopper = User.find(3)
- end
-
- test 'object_daddy creation' do
- User.generate_with_protected!(:firstname => 'Testing connection')
- User.generate_with_protected!(:firstname => 'Testing connection')
- assert_equal 2, User.count(:all, :conditions => {:firstname => 'Testing connection'})
- end
-
- def test_truth
- assert_kind_of User, @jsmith
- end
-
- def test_mail_should_be_stripped
- u = User.new
- u.mail = " foo@bar.com "
- assert_equal "foo@bar.com", u.mail
- end
-
- def test_mail_validation
- u = User.new
- u.mail = ''
- assert !u.valid?
- assert_equal I18n.translate('activerecord.errors.messages.blank'), u.errors.on(:mail)
- end
-
- def test_create
- user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
-
- user.login = "jsmith"
- user.password, user.password_confirmation = "password", "password"
- # login uniqueness
- assert !user.save
- assert_equal 1, user.errors.count
-
- user.login = "newuser"
- user.password, user.password_confirmation = "passwd", "password"
- # password confirmation
- assert !user.save
- assert_equal 1, user.errors.count
-
- user.password, user.password_confirmation = "password", "password"
- assert user.save
- end
-
- context "User#before_create" do
- should "set the mail_notification to the default Setting" do
- @user1 = User.generate_with_protected!
- assert_equal 'only_my_events', @user1.mail_notification
-
- with_settings :default_notification_option => 'all' do
- @user2 = User.generate_with_protected!
- assert_equal 'all', @user2.mail_notification
- end
- end
- end
-
- context "User.login" do
- should "be case-insensitive." do
- u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
- u.login = 'newuser'
- u.password, u.password_confirmation = "password", "password"
- assert u.save
-
- u = User.new(:firstname => "Similar", :lastname => "User", :mail => "similaruser@somenet.foo")
- u.login = 'NewUser'
- u.password, u.password_confirmation = "password", "password"
- assert !u.save
- assert_equal I18n.translate('activerecord.errors.messages.taken'), u.errors.on(:login)
- end
- end
-
- def test_mail_uniqueness_should_not_be_case_sensitive
- u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
- u.login = 'newuser1'
- u.password, u.password_confirmation = "password", "password"
- assert u.save
-
- u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo")
- u.login = 'newuser2'
- u.password, u.password_confirmation = "password", "password"
- assert !u.save
- assert_equal I18n.translate('activerecord.errors.messages.taken'), u.errors.on(:mail)
- end
-
- def test_update
- assert_equal "admin", @admin.login
- @admin.login = "john"
- assert @admin.save, @admin.errors.full_messages.join("; ")
- @admin.reload
- assert_equal "john", @admin.login
- end
-
- def test_destroy_should_delete_members_and_roles
- members = Member.find_all_by_user_id(2)
- ms = members.size
- rs = members.collect(&:roles).flatten.size
-
- assert_difference 'Member.count', - ms do
- assert_difference 'MemberRole.count', - rs do
- User.find(2).destroy
- end
- end
-
- assert_nil User.find_by_id(2)
- assert Member.find_all_by_user_id(2).empty?
- end
-
- def test_destroy_should_update_attachments
- attachment = Attachment.create!(:container => Project.find(1),
- :file => uploaded_test_file("testfile.txt", "text/plain"),
- :author_id => 2)
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous, attachment.reload.author
- end
-
- def test_destroy_should_update_comments
- comment = Comment.create!(
- :commented => News.create!(:project_id => 1, :author_id => 1, :title => 'foo', :description => 'foo'),
- :author => User.find(2),
- :comments => 'foo'
- )
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous, comment.reload.author
- end
-
- def test_destroy_should_update_issues
- issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous, issue.reload.author
- end
-
- def test_destroy_should_unassign_issues
- issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_nil issue.reload.assigned_to
- end
-
- def test_destroy_should_update_journals
- issue = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'foo')
- issue.init_journal(User.find(2), "update")
- issue.save!
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous, issue.journals.first.reload.user
- end
-
- def test_destroy_should_update_journal_details_old_value
- issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
- issue.init_journal(User.find(1), "update")
- issue.assigned_to_id = nil
- assert_difference 'JournalDetail.count' do
- issue.save!
- end
- journal_detail = JournalDetail.first(:order => 'id DESC')
- assert_equal '2', journal_detail.old_value
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value
- end
-
- def test_destroy_should_update_journal_details_value
- issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
- issue.init_journal(User.find(1), "update")
- issue.assigned_to_id = 2
- assert_difference 'JournalDetail.count' do
- issue.save!
- end
- journal_detail = JournalDetail.first(:order => 'id DESC')
- assert_equal '2', journal_detail.value
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous.id.to_s, journal_detail.reload.value
- end
-
- def test_destroy_should_update_messages
- board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board')
- message = Message.create!(:board_id => board.id, :author_id => 2, :subject => 'foo', :content => 'foo')
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous, message.reload.author
- end
-
- def test_destroy_should_update_news
- news = News.create!(:project_id => 1, :author_id => 2, :title => 'foo', :description => 'foo')
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous, news.reload.author
- end
-
- def test_destroy_should_delete_private_queries
- query = Query.new(:name => 'foo', :is_public => false)
- query.project_id = 1
- query.user_id = 2
- query.save!
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_nil Query.find_by_id(query.id)
- end
-
- def test_destroy_should_update_public_queries
- query = Query.new(:name => 'foo', :is_public => true)
- query.project_id = 1
- query.user_id = 2
- query.save!
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous, query.reload.user
- end
-
- def test_destroy_should_update_time_entries
- entry = TimeEntry.new(:hours => '2', :spent_on => Date.today, :activity => TimeEntryActivity.create!(:name => 'foo'))
- entry.project_id = 1
- entry.user_id = 2
- entry.save!
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous, entry.reload.user
- end
-
- def test_destroy_should_delete_tokens
- token = Token.create!(:user_id => 2, :value => 'foo')
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_nil Token.find_by_id(token.id)
- end
-
- def test_destroy_should_delete_watchers
- issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'foo')
- watcher = Watcher.create!(:user_id => 2, :watchable => issue)
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_nil Watcher.find_by_id(watcher.id)
- end
-
- def test_destroy_should_update_wiki_contents
- wiki_content = WikiContent.create!(
- :text => 'foo',
- :author_id => 2,
- :page => WikiPage.create!(:title => 'Foo', :wiki => Wiki.create!(:project_id => 1, :start_page => 'Start'))
- )
- wiki_content.text = 'bar'
- assert_difference 'WikiContent::Version.count' do
- wiki_content.save!
- end
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_equal User.anonymous, wiki_content.reload.author
- wiki_content.versions.each do |version|
- assert_equal User.anonymous, version.reload.author
- end
- end
-
- def test_destroy_should_nullify_issue_categories
- category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo')
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_nil category.reload.assigned_to_id
- end
-
- def test_destroy_should_nullify_changesets
- changeset = Changeset.create!(
- :repository => Repository::Subversion.create!(
- :project_id => 1,
- :url => 'file:///var/svn'
- ),
- :revision => '12',
- :committed_on => Time.now,
- :committer => 'jsmith'
- )
- assert_equal 2, changeset.user_id
-
- User.find(2).destroy
- assert_nil User.find_by_id(2)
- assert_nil changeset.reload.user_id
- end
-
- def test_anonymous_user_should_not_be_destroyable
- assert_no_difference 'User.count' do
- assert_equal false, User.anonymous.destroy
- end
- end
-
- def test_validate_login_presence
- @admin.login = ""
- assert !@admin.save
- assert_equal 1, @admin.errors.count
- end
-
- def test_validate_mail_notification_inclusion
- u = User.new
- u.mail_notification = 'foo'
- u.save
- assert_not_nil u.errors[:mail_notification]
- end
-
- context "User#try_to_login" do
- should "fall-back to case-insensitive if user login is not found as-typed." do
- user = User.try_to_login("AdMin", "admin")
- assert_kind_of User, user
- assert_equal "admin", user.login
- end
-
- should "select the exact matching user first" do
- case_sensitive_user = User.generate_with_protected!(
- :login => 'changed', :password => 'admin',
- :password_confirmation => 'admin')
- # bypass validations to make it appear like existing data
- case_sensitive_user.update_attribute(:login, 'ADMIN')
-
- user = User.try_to_login("ADMIN", "admin")
- assert_kind_of User, user
- assert_equal "ADMIN", user.login
-
- end
- end
-
- def test_password
- user = User.try_to_login("admin", "admin")
- assert_kind_of User, user
- assert_equal "admin", user.login
- user.password = "hello"
- assert user.save
-
- user = User.try_to_login("admin", "hello")
- assert_kind_of User, user
- assert_equal "admin", user.login
- end
-
- def test_validate_password_length
- with_settings :password_min_length => '100' do
- user = User.new(:firstname => "new100", :lastname => "user100", :mail => "newuser100@somenet.foo")
- user.login = "newuser100"
- user.password, user.password_confirmation = "password100", "password100"
- assert !user.save
- assert_equal 1, user.errors.count
- end
- end
-
- def test_name_format
- assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
- Setting.user_format = :firstname_lastname
- assert_equal 'John Smith', @jsmith.reload.name
- Setting.user_format = :username
- assert_equal 'jsmith', @jsmith.reload.name
- end
-
- def test_fields_for_order_statement_should_return_fields_according_user_format_setting
- with_settings :user_format => 'lastname_coma_firstname' do
- assert_equal ['users.lastname', 'users.firstname', 'users.id'], User.fields_for_order_statement
- end
- end
-
- def test_fields_for_order_statement_width_table_name_should_prepend_table_name
- with_settings :user_format => 'lastname_firstname' do
- assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'], User.fields_for_order_statement('authors')
- end
- end
-
- def test_fields_for_order_statement_with_blank_format_should_return_default
- with_settings :user_format => '' do
- assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
- end
- end
-
- def test_fields_for_order_statement_with_invalid_format_should_return_default
- with_settings :user_format => 'foo' do
- assert_equal ['users.firstname', 'users.lastname', 'users.id'], User.fields_for_order_statement
- end
- end
-
- def test_lock
- user = User.try_to_login("jsmith", "jsmith")
- assert_equal @jsmith, user
-
- @jsmith.status = User::STATUS_LOCKED
- assert @jsmith.save
-
- user = User.try_to_login("jsmith", "jsmith")
- assert_equal nil, user
- end
-
- context ".try_to_login" do
- context "with good credentials" do
- should "return the user" do
- user = User.try_to_login("admin", "admin")
- assert_kind_of User, user
- assert_equal "admin", user.login
- end
- end
-
- context "with wrong credentials" do
- should "return nil" do
- assert_nil User.try_to_login("admin", "foo")
- end
- end
- end
-
- if ldap_configured?
- context "#try_to_login using LDAP" do
- context "with failed connection to the LDAP server" do
- should "return nil" do
- @auth_source = AuthSourceLdap.find(1)
- AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect')
-
- assert_equal nil, User.try_to_login('edavis', 'wrong')
- end
- end
-
- context "with an unsuccessful authentication" do
- should "return nil" do
- assert_equal nil, User.try_to_login('edavis', 'wrong')
- end
- end
-
- context "on the fly registration" do
- setup do
- @auth_source = AuthSourceLdap.find(1)
- end
-
- context "with a successful authentication" do
- should "create a new user account if it doesn't exist" do
- assert_difference('User.count') do
- user = User.try_to_login('edavis', '123456')
- assert !user.admin?
- end
- end
-
- should "retrieve existing user" do
- user = User.try_to_login('edavis', '123456')
- user.admin = true
- user.save!
-
- assert_no_difference('User.count') do
- user = User.try_to_login('edavis', '123456')
- assert user.admin?
- end
- end
- end
- end
- end
-
- else
- puts "Skipping LDAP tests."
- end
-
- def test_create_anonymous
- AnonymousUser.delete_all
- anon = User.anonymous
- assert !anon.new_record?
- assert_kind_of AnonymousUser, anon
- end
-
- def test_ensure_single_anonymous_user
- AnonymousUser.delete_all
- anon1 = User.anonymous
- assert !anon1.new_record?
- assert_kind_of AnonymousUser, anon1
- anon2 = AnonymousUser.create(
- :lastname => 'Anonymous', :firstname => '',
- :mail => '', :login => '', :status => 0)
- assert_equal 1, anon2.errors.count
- end
-
- should_have_one :rss_token
-
- def test_rss_key
- assert_nil @jsmith.rss_token
- key = @jsmith.rss_key
- assert_equal 40, key.length
-
- @jsmith.reload
- assert_equal key, @jsmith.rss_key
- end
-
-
- should_have_one :api_token
-
- context "User#api_key" do
- should "generate a new one if the user doesn't have one" do
- user = User.generate_with_protected!(:api_token => nil)
- assert_nil user.api_token
-
- key = user.api_key
- assert_equal 40, key.length
- user.reload
- assert_equal key, user.api_key
- end
-
- should "return the existing api token value" do
- user = User.generate_with_protected!
- token = Token.generate!(:action => 'api')
- user.api_token = token
- assert user.save
-
- assert_equal token.value, user.api_key
- end
- end
-
- context "User#find_by_api_key" do
- should "return nil if no matching key is found" do
- assert_nil User.find_by_api_key('zzzzzzzzz')
- end
-
- should "return nil if the key is found for an inactive user" do
- user = User.generate_with_protected!(:status => User::STATUS_LOCKED)
- token = Token.generate!(:action => 'api')
- user.api_token = token
- user.save
-
- assert_nil User.find_by_api_key(token.value)
- end
-
- should "return the user if the key is found for an active user" do
- user = User.generate_with_protected!(:status => User::STATUS_ACTIVE)
- token = Token.generate!(:action => 'api')
- user.api_token = token
- user.save
-
- assert_equal user, User.find_by_api_key(token.value)
- end
- end
-
- def test_roles_for_project
- # user with a role
- roles = @jsmith.roles_for_project(Project.find(1))
- assert_kind_of Role, roles.first
- assert_equal "Manager", roles.first.name
-
- # user with no role
- assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?}
- end
-
- def test_projects_by_role_for_user_with_role
- user = User.find(2)
- assert_kind_of Hash, user.projects_by_role
- assert_equal 2, user.projects_by_role.size
- assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort
- assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort
- end
-
- def test_projects_by_role_for_user_with_no_role
- user = User.generate!
- assert_equal({}, user.projects_by_role)
- end
-
- def test_projects_by_role_for_anonymous
- assert_equal({}, User.anonymous.projects_by_role)
- end
-
- def test_valid_notification_options
- # without memberships
- assert_equal 5, User.find(7).valid_notification_options.size
- # with memberships
- assert_equal 6, User.find(2).valid_notification_options.size
- end
-
- def test_valid_notification_options_class_method
- assert_equal 5, User.valid_notification_options.size
- assert_equal 5, User.valid_notification_options(User.find(7)).size
- assert_equal 6, User.valid_notification_options(User.find(2)).size
- end
-
- def test_mail_notification_all
- @jsmith.mail_notification = 'all'
- @jsmith.notified_project_ids = []
- @jsmith.save
- @jsmith.reload
- assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
- end
-
- def test_mail_notification_selected
- @jsmith.mail_notification = 'selected'
- @jsmith.notified_project_ids = [1]
- @jsmith.save
- @jsmith.reload
- assert Project.find(1).recipients.include?(@jsmith.mail)
- end
-
- def test_mail_notification_only_my_events
- @jsmith.mail_notification = 'only_my_events'
- @jsmith.notified_project_ids = []
- @jsmith.save
- @jsmith.reload
- assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
- end
-
- def test_comments_sorting_preference
- assert !@jsmith.wants_comments_in_reverse_order?
- @jsmith.pref.comments_sorting = 'asc'
- assert !@jsmith.wants_comments_in_reverse_order?
- @jsmith.pref.comments_sorting = 'desc'
- assert @jsmith.wants_comments_in_reverse_order?
- end
-
- def test_find_by_mail_should_be_case_insensitive
- u = User.find_by_mail('JSmith@somenet.foo')
- assert_not_nil u
- assert_equal 'jsmith@somenet.foo', u.mail
- end
-
- def test_random_password
- u = User.new
- u.random_password
- assert !u.password.blank?
- assert !u.password_confirmation.blank?
- end
-
- context "#change_password_allowed?" do
- should "be allowed if no auth source is set" do
- user = User.generate_with_protected!
- assert user.change_password_allowed?
- end
-
- should "delegate to the auth source" do
- user = User.generate_with_protected!
-
- allowed_auth_source = AuthSource.generate!
- def allowed_auth_source.allow_password_changes?; true; end
-
- denied_auth_source = AuthSource.generate!
- def denied_auth_source.allow_password_changes?; false; end
-
- assert user.change_password_allowed?
-
- user.auth_source = allowed_auth_source
- assert user.change_password_allowed?, "User not allowed to change password, though auth source does"
-
- user.auth_source = denied_auth_source
- assert !user.change_password_allowed?, "User allowed to change password, though auth source does not"
- end
-
- end
-
- context "#allowed_to?" do
- context "with a unique project" do
- should "return false if project is archived" do
- project = Project.find(1)
- Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED)
- assert ! @admin.allowed_to?(:view_issues, Project.find(1))
- end
-
- should "return false if related module is disabled" do
- project = Project.find(1)
- project.enabled_module_names = ["issue_tracking"]
- assert @admin.allowed_to?(:add_issues, project)
- assert ! @admin.allowed_to?(:view_wiki_pages, project)
- end
-
- should "authorize nearly everything for admin users" do
- project = Project.find(1)
- assert ! @admin.member_of?(project)
- %w(edit_issues delete_issues manage_news manage_documents manage_wiki).each do |p|
- assert @admin.allowed_to?(p.to_sym, project)
- end
- end
-
- should "authorize normal users depending on their roles" do
- project = Project.find(1)
- assert @jsmith.allowed_to?(:delete_messages, project) #Manager
- assert ! @dlopper.allowed_to?(:delete_messages, project) #Developper
- end
- end
-
- context "with multiple projects" do
- should "return false if array is empty" do
- assert ! @admin.allowed_to?(:view_project, [])
- end
-
- should "return true only if user has permission on all these projects" do
- assert @admin.allowed_to?(:view_project, Project.all)
- assert ! @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
- assert @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
- assert ! @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
- end
-
- should "behave correctly with arrays of 1 project" do
- assert ! User.anonymous.allowed_to?(:delete_issues, [Project.first])
- end
- end
-
- context "with options[:global]" do
- should "authorize if user has at least one role that has this permission" do
- @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere
- @anonymous = User.find(6)
- assert @jsmith.allowed_to?(:delete_issue_watchers, nil, :global => true)
- assert ! @dlopper2.allowed_to?(:delete_issue_watchers, nil, :global => true)
- assert @dlopper2.allowed_to?(:add_issues, nil, :global => true)
- assert ! @anonymous.allowed_to?(:add_issues, nil, :global => true)
- assert @anonymous.allowed_to?(:view_issues, nil, :global => true)
- end
- end
- end
-
- context "User#notify_about?" do
- context "Issues" do
- setup do
- @project = Project.find(1)
- @author = User.generate_with_protected!
- @assignee = User.generate_with_protected!
- @issue = Issue.generate_for_project!(@project, :assigned_to => @assignee, :author => @author)
- end
-
- should "be true for a user with :all" do
- @author.update_attribute(:mail_notification, 'all')
- assert @author.notify_about?(@issue)
- end
-
- should "be false for a user with :none" do
- @author.update_attribute(:mail_notification, 'none')
- assert ! @author.notify_about?(@issue)
- end
-
- should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do
- @user = User.generate_with_protected!(:mail_notification => 'only_my_events')
- Member.create!(:user => @user, :project => @project, :role_ids => [1])
- assert ! @user.notify_about?(@issue)
- end
-
- should "be true for a user with :only_my_events and is the author" do
- @author.update_attribute(:mail_notification, 'only_my_events')
- assert @author.notify_about?(@issue)
- end
-
- should "be true for a user with :only_my_events and is the assignee" do
- @assignee.update_attribute(:mail_notification, 'only_my_events')
- assert @assignee.notify_about?(@issue)
- end
-
- should "be true for a user with :only_assigned and is the assignee" do
- @assignee.update_attribute(:mail_notification, 'only_assigned')
- assert @assignee.notify_about?(@issue)
- end
-
- should "be false for a user with :only_assigned and is not the assignee" do
- @author.update_attribute(:mail_notification, 'only_assigned')
- assert ! @author.notify_about?(@issue)
- end
-
- should "be true for a user with :only_owner and is the author" do
- @author.update_attribute(:mail_notification, 'only_owner')
- assert @author.notify_about?(@issue)
- end
-
- should "be false for a user with :only_owner and is not the author" do
- @assignee.update_attribute(:mail_notification, 'only_owner')
- assert ! @assignee.notify_about?(@issue)
- end
-
- should "be true for a user with :selected and is the author" do
- @author.update_attribute(:mail_notification, 'selected')
- assert @author.notify_about?(@issue)
- end
-
- should "be true for a user with :selected and is the assignee" do
- @assignee.update_attribute(:mail_notification, 'selected')
- assert @assignee.notify_about?(@issue)
- end
-
- should "be false for a user with :selected and is not the author or assignee" do
- @user = User.generate_with_protected!(:mail_notification => 'selected')
- Member.create!(:user => @user, :project => @project, :role_ids => [1])
- assert ! @user.notify_about?(@issue)
- end
- end
-
- context "other events" do
- should 'be added and tested'
- end
- end
-
- def test_salt_unsalted_passwords
- # Restore a user with an unsalted password
- user = User.find(1)
- user.salt = nil
- user.hashed_password = User.hash_password("unsalted")
- user.save!
-
- User.salt_unsalted_passwords!
-
- user.reload
- # Salt added
- assert !user.salt.blank?
- # Password still valid
- assert user.check_password?("unsalted")
- assert_equal user, User.try_to_login(user.login, "unsalted")
- end
-
- if Object.const_defined?(:OpenID)
-
- def test_setting_identity_url
- normalized_open_id_url = 'http://example.com/'
- u = User.new( :identity_url => 'http://example.com/' )
- assert_equal normalized_open_id_url, u.identity_url
- end
-
- def test_setting_identity_url_without_trailing_slash
- normalized_open_id_url = 'http://example.com/'
- u = User.new( :identity_url => 'http://example.com' )
- assert_equal normalized_open_id_url, u.identity_url
- end
-
- def test_setting_identity_url_without_protocol
- normalized_open_id_url = 'http://example.com/'
- u = User.new( :identity_url => 'example.com' )
- assert_equal normalized_open_id_url, u.identity_url
- end
-
- def test_setting_blank_identity_url
- u = User.new( :identity_url => 'example.com' )
- u.identity_url = ''
- assert u.identity_url.blank?
- end
-
- def test_setting_invalid_identity_url
- u = User.new( :identity_url => 'this is not an openid url' )
- assert u.identity_url.blank?
- end
-
- else
- puts "Skipping openid tests."
- end
-
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/57/57a3ca6236cc4e5539fa3337ae1a20668f37ff47.svn-base
--- a/.svn/pristine/57/57a3ca6236cc4e5539fa3337ae1a20668f37ff47.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class VersionsController < ApplicationController
- menu_item :roadmap
- model_object Version
- before_filter :find_model_object, :except => [:index, :new, :create, :close_completed]
- before_filter :find_project_from_association, :except => [:index, :new, :create, :close_completed]
- before_filter :find_project, :only => [:index, :new, :create, :close_completed]
- before_filter :authorize
-
- accept_api_auth :index, :create, :update, :destroy
-
- helper :custom_fields
- helper :projects
-
- def index
- respond_to do |format|
- format.html {
- @trackers = @project.trackers.find(:all, :order => 'position')
- retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?})
- @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
- project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
-
- @versions = @project.shared_versions || []
- @versions += @project.rolled_up_versions.visible if @with_subprojects
- @versions = @versions.uniq.sort
- @versions.reject! {|version| version.closed? || version.completed? } unless params[:completed]
-
- @issues_by_version = {}
- unless @selected_tracker_ids.empty?
- @versions.each do |version|
- issues = version.fixed_issues.visible.find(:all,
- :include => [:project, :status, :tracker, :priority],
- :conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids},
- :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
- @issues_by_version[version] = issues
- end
- end
- @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
- }
- format.api {
- @versions = @project.shared_versions.all
- }
- end
- end
-
- def show
- respond_to do |format|
- format.html {
- @issues = @version.fixed_issues.visible.find(:all,
- :include => [:status, :tracker, :priority],
- :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
- }
- format.api
- end
- end
-
- def new
- @version = @project.versions.build
- if params[:version]
- attributes = params[:version].dup
- attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
- @version.attributes = attributes
- end
- end
-
- def create
- # TODO: refactor with code above in #new
- @version = @project.versions.build
- if params[:version]
- attributes = params[:version].dup
- attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
- @version.attributes = attributes
- end
-
- if request.post?
- if @version.save
- respond_to do |format|
- format.html do
- flash[:notice] = l(:notice_successful_create)
- redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
- end
- format.js do
- # IE doesn't support the replace_html rjs method for select box options
- render(:update) {|page| page.replace "issue_fixed_version_id",
- content_tag('select', ' ' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]')
- }
- end
- format.api do
- render :action => 'show', :status => :created, :location => version_url(@version)
- end
- end
- else
- respond_to do |format|
- format.html { render :action => 'new' }
- format.js do
- render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) }
- end
- format.api { render_validation_errors(@version) }
- end
- end
- end
- end
-
- def edit
- end
-
- def update
- if request.put? && params[:version]
- attributes = params[:version].dup
- attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
- if @version.update_attributes(attributes)
- respond_to do |format|
- format.html {
- flash[:notice] = l(:notice_successful_update)
- redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
- }
- format.api { head :ok }
- end
- else
- respond_to do |format|
- format.html { render :action => 'edit' }
- format.api { render_validation_errors(@version) }
- end
- end
- end
- end
-
- def close_completed
- if request.put?
- @project.close_completed_versions
- end
- redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
- end
-
- verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
- def destroy
- if @version.fixed_issues.empty?
- @version.destroy
- respond_to do |format|
- format.html { redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project }
- format.api { head :ok }
- end
- else
- respond_to do |format|
- format.html {
- flash[:error] = l(:notice_unable_delete_version)
- redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
- }
- format.api { head :unprocessable_entity }
- end
- end
- end
-
- def status_by
- respond_to do |format|
- format.html { render :action => 'show' }
- format.js { render(:update) {|page| page.replace_html 'status_by', render_issue_status_by(@version, params[:status_by])} }
- end
- end
-
-private
- def find_project
- @project = Project.find(params[:project_id])
- rescue ActiveRecord::RecordNotFound
- render_404
- end
-
- def retrieve_selected_tracker_ids(selectable_trackers, default_trackers=nil)
- if ids = params[:tracker_ids]
- @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s }
- else
- @selected_tracker_ids = (default_trackers || selectable_trackers).collect {|t| t.id.to_s }
- end
- end
-
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/5f/5f2c1ff7bb00e3dbe21424d6a9413b8369316e8a.svn-base
--- a/.svn/pristine/5f/5f2c1ff7bb00e3dbe21424d6a9413b8369316e8a.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-class MemberRole < ActiveRecord::Base
- generator_for :member, :method => :generate_member
- generator_for :role, :method => :generate_role
-
- def self.generate_role
- Role.generate!
- end
-
- def self.generate_member
- Member.generate!
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/60/60b442ee90e3b26f595ed2865e1f3dfc9222dd1c.svn-base
--- a/.svn/pristine/60/60b442ee90e3b26f595ed2865e1f3dfc9222dd1c.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class Comment < ActiveRecord::Base
- belongs_to :commented, :polymorphic => true, :counter_cache => true
- belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
-
- validates_presence_of :commented, :author, :comments
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/64/6453475106e156ddd20fc32236e1e2b88b1df72a.svn-base
--- a/.svn/pristine/64/6453475106e156ddd20fc32236e1e2b88b1df72a.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-module ProjectsHelper
- def link_to_version(version, options = {})
- return '' unless version && version.is_a?(Version)
- link_to_if version.visible?, format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options
- end
-
- def project_settings_tabs
- tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural},
- {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural},
- {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural},
- {:name => 'versions', :action => :manage_versions, :partial => 'projects/settings/versions', :label => :label_version_plural},
- {:name => 'categories', :action => :manage_categories, :partial => 'projects/settings/issue_categories', :label => :label_issue_category_plural},
- {:name => 'wiki', :action => :manage_wiki, :partial => 'projects/settings/wiki', :label => :label_wiki},
- {:name => 'repository', :action => :manage_repository, :partial => 'projects/settings/repository', :label => :label_repository},
- {:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural},
- {:name => 'activities', :action => :manage_project_activities, :partial => 'projects/settings/activities', :label => :enumeration_activities}
- ]
- tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)}
- end
-
- def parent_project_select_tag(project)
- selected = project.parent
- # retrieve the requested parent project
- parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id]
- if parent_id
- selected = (parent_id.blank? ? nil : Project.find(parent_id))
- end
-
- options = ''
- options << " " if project.allowed_parents.include?(nil)
- options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected)
- content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id')
- end
-
- # Renders a tree of projects as a nested set of unordered lists
- # The given collection may be a subset of the whole project tree
- # (eg. some intermediate nodes are private and can not be seen)
- def render_project_hierarchy(projects)
- s = ''
- if projects.any?
- ancestors = []
- original_project = @project
- projects.each do |project|
- # set the project environment to please macros.
- @project = project
- if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
- s << " \n"
- else
- ancestors.pop
- s << ""
- while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
- ancestors.pop
- s << " \n"
- end
- end
- classes = (ancestors.empty? ? 'root' : 'child')
- s << "" +
- link_to_project(project, {}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}")
- s << "
#{textilizable(project.short_description, :project => project)}
" unless project.description.blank?
- s << "
\n"
- ancestors << project
- end
- s << (" \n" * ancestors.size)
- @project = original_project
- end
- s.html_safe
- end
-
- # Returns a set of options for a select field, grouped by project.
- def version_options_for_select(versions, selected=nil)
- grouped = Hash.new {|h,k| h[k] = []}
- versions.each do |version|
- grouped[version.project.name] << [version.name, version.id]
- end
- # Add in the selected
- if selected && !versions.include?(selected)
- grouped[selected.project.name] << [selected.name, selected.id]
- end
-
- if grouped.keys.size > 1
- grouped_options_for_select(grouped, selected && selected.id)
- else
- options_for_select((grouped.values.first || []), selected && selected.id)
- end
- end
-
- def format_version_sharing(sharing)
- sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing)
- l("label_version_sharing_#{sharing}")
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/65/6514caff2f9e9a210142d5cdd20b0807c7fb9b2f.svn-base
--- a/.svn/pristine/65/6514caff2f9e9a210142d5cdd20b0807c7fb9b2f.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-module IssueCategoriesHelper
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/69/69f952b81bb3ec0bda0f3e3b36510faab9da8bc9.svn-base
--- a/.svn/pristine/69/69f952b81bb3ec0bda0f3e3b36510faab9da8bc9.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class MembersController < ApplicationController
- model_object Member
- before_filter :find_model_object, :except => [:new, :autocomplete_for_member]
- before_filter :find_project_from_association, :except => [:new, :autocomplete_for_member]
- before_filter :find_project, :only => [:new, :autocomplete_for_member]
- before_filter :authorize
-
- def new
- members = []
- if params[:member] && request.post?
- attrs = params[:member].dup
- if (user_ids = attrs.delete(:user_ids))
- user_ids.each do |user_id|
- members << Member.new(attrs.merge(:user_id => user_id))
- end
- else
- members << Member.new(attrs)
- end
- @project.members << members
- end
- respond_to do |format|
- if members.present? && members.all? {|m| m.valid? }
-
- format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
-
- format.js {
- render(:update) {|page|
- page.replace_html "tab-content-members", :partial => 'projects/settings/members'
- page << 'hideOnLoad()'
- members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") }
- }
- }
- else
-
- format.js {
- render(:update) {|page|
- errors = members.collect {|m|
- m.errors.full_messages
- }.flatten.uniq
-
- page.alert(l(:notice_failed_to_save_members, :errors => errors.join(', ')))
- }
- }
-
- end
- end
- end
-
- def edit
- if request.post? and @member.update_attributes(params[:member])
- respond_to do |format|
- format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
- format.js {
- render(:update) {|page|
- page.replace_html "tab-content-members", :partial => 'projects/settings/members'
- page << 'hideOnLoad()'
- page.visual_effect(:highlight, "member-#{@member.id}")
- }
- }
- end
- end
- end
-
- def destroy
- if request.post? && @member.deletable?
- @member.destroy
- end
- respond_to do |format|
- format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
- format.js { render(:update) {|page|
- page.replace_html "tab-content-members", :partial => 'projects/settings/members'
- page << 'hideOnLoad()'
- }
- }
- end
- end
-
- def autocomplete_for_member
- @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals
- render :layout => false
- end
-
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/6a/6a446c0fabce93b01244d29a3a538026070a8b28.svn-base
--- a/.svn/pristine/6a/6a446c0fabce93b01244d29a3a538026070a8b28.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class IssueCategoriesController < ApplicationController
- menu_item :settings
- model_object IssueCategory
- before_filter :find_model_object, :except => [:index, :new, :create]
- before_filter :find_project_from_association, :except => [:index, :new, :create]
- before_filter :find_project, :only => [:index, :new, :create]
- before_filter :authorize
- accept_api_auth :index, :show, :create, :update, :destroy
-
- def index
- respond_to do |format|
- format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project }
- format.api { @categories = @project.issue_categories.all }
- end
- end
-
- def show
- respond_to do |format|
- format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project }
- format.api
- end
- end
-
- def new
- @category = @project.issue_categories.build(params[:issue_category])
- end
-
- verify :method => :post, :only => :create
- def create
- @category = @project.issue_categories.build(params[:issue_category])
- if @category.save
- respond_to do |format|
- format.html do
- flash[:notice] = l(:notice_successful_create)
- redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
- end
- format.js do
- # IE doesn't support the replace_html rjs method for select box options
- render(:update) {|page| page.replace "issue_category_id",
- content_tag('select', ' ' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]')
- }
- end
- format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) }
- end
- else
- respond_to do |format|
- format.html { render :action => 'new'}
- format.js do
- render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) }
- end
- format.api { render_validation_errors(@category) }
- end
- end
- end
-
- def edit
- end
-
- verify :method => :put, :only => :update
- def update
- if @category.update_attributes(params[:issue_category])
- respond_to do |format|
- format.html {
- flash[:notice] = l(:notice_successful_update)
- redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
- }
- format.api { head :ok }
- end
- else
- respond_to do |format|
- format.html { render :action => 'edit' }
- format.api { render_validation_errors(@category) }
- end
- end
- end
-
- verify :method => :delete, :only => :destroy
- def destroy
- @issue_count = @category.issues.size
- if @issue_count == 0 || params[:todo] || api_request?
- reassign_to = nil
- if params[:reassign_to_id] && (params[:todo] == 'reassign' || params[:todo].blank?)
- reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id])
- end
- @category.destroy(reassign_to)
- respond_to do |format|
- format.html { redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' }
- format.api { head :ok }
- end
- return
- end
- @categories = @project.issue_categories - [@category]
- end
-
-private
- # Wrap ApplicationController's find_model_object method to set
- # @category instead of just @issue_category
- def find_model_object
- super
- @category = @object
- end
-
- def find_project
- @project = Project.find(params[:project_id])
- rescue ActiveRecord::RecordNotFound
- render_404
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/6c/6c1e26b54fdd47501d3a107c6cb94b31dc942cde.svn-base
--- a/.svn/pristine/6c/6c1e26b54fdd47501d3a107c6cb94b31dc942cde.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-module RolesHelper
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/6c/6c4dd8ce0226a8bc5d18fafda9466bf4106576da.svn-base
--- a/.svn/pristine/6c/6c4dd8ce0226a8bc5d18fafda9466bf4106576da.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1062 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require 'forwardable'
-require 'cgi'
-
-module ApplicationHelper
- include Redmine::WikiFormatting::Macros::Definitions
- include Redmine::I18n
- include GravatarHelper::PublicMethods
-
- extend Forwardable
- def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
-
- # Return true if user is authorized for controller/action, otherwise false
- def authorize_for(controller, action)
- User.current.allowed_to?({:controller => controller, :action => action}, @project)
- end
-
- # Display a link if user is authorized
- #
- # @param [String] name Anchor text (passed to link_to)
- # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized
- # @param [optional, Hash] html_options Options passed to link_to
- # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to
- def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
- link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action])
- end
-
- # Display a link to remote if user is authorized
- def link_to_remote_if_authorized(name, options = {}, html_options = nil)
- url = options[:url] || {}
- link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action])
- end
-
- # Displays a link to user's account page if active
- def link_to_user(user, options={})
- if user.is_a?(User)
- name = h(user.name(options[:format]))
- if user.active?
- link_to name, :controller => 'users', :action => 'show', :id => user
- else
- name
- end
- else
- h(user.to_s)
- end
- end
-
- # Displays a link to +issue+ with its subject.
- # Examples:
- #
- # link_to_issue(issue) # => Defect #6: This is the subject
- # link_to_issue(issue, :truncate => 6) # => Defect #6: This i...
- # link_to_issue(issue, :subject => false) # => Defect #6
- # link_to_issue(issue, :project => true) # => Foo - Defect #6
- #
- def link_to_issue(issue, options={})
- title = nil
- subject = nil
- if options[:subject] == false
- title = truncate(issue.subject, :length => 60)
- else
- subject = issue.subject
- if options[:truncate]
- subject = truncate(subject, :length => options[:truncate])
- end
- end
- s = link_to "#{h(issue.tracker)} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
- :class => issue.css_classes,
- :title => title
- s << ": #{h subject}" if subject
- s = "#{h issue.project} - " + s if options[:project]
- s
- end
-
- # Generates a link to an attachment.
- # Options:
- # * :text - Link text (default to attachment filename)
- # * :download - Force download (default: false)
- def link_to_attachment(attachment, options={})
- text = options.delete(:text) || attachment.filename
- action = options.delete(:download) ? 'download' : 'show'
- link_to(h(text),
- {:controller => 'attachments', :action => action,
- :id => attachment, :filename => attachment.filename },
- options)
- end
-
- # Generates a link to a SCM revision
- # Options:
- # * :text - Link text (default to the formatted revision)
- def link_to_revision(revision, project, options={})
- text = options.delete(:text) || format_revision(revision)
- rev = revision.respond_to?(:identifier) ? revision.identifier : revision
-
- link_to(h(text), {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev},
- :title => l(:label_revision_id, format_revision(revision)))
- end
-
- # Generates a link to a message
- def link_to_message(message, options={}, html_options = nil)
- link_to(
- h(truncate(message.subject, :length => 60)),
- { :controller => 'messages', :action => 'show',
- :board_id => message.board_id,
- :id => message.root,
- :r => (message.parent_id && message.id),
- :anchor => (message.parent_id ? "message-#{message.id}" : nil)
- }.merge(options),
- html_options
- )
- end
-
- # Generates a link to a project if active
- # Examples:
- #
- # link_to_project(project) # => link to the specified project overview
- # link_to_project(project, :action=>'settings') # => link to project settings
- # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
- # link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
- #
- def link_to_project(project, options={}, html_options = nil)
- if project.active?
- url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
- link_to(h(project), url, html_options)
- else
- h(project)
- end
- end
-
- def toggle_link(name, id, options={})
- onclick = "Element.toggle('#{id}'); "
- onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
- onclick << "return false;"
- link_to(name, "#", :onclick => onclick)
- end
-
- def image_to_function(name, function, html_options = {})
- html_options.symbolize_keys!
- tag(:input, html_options.merge({
- :type => "image", :src => image_path(name),
- :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
- }))
- end
-
- def prompt_to_remote(name, text, param, url, html_options = {})
- html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;"
- link_to name, {}, html_options
- end
-
- def format_activity_title(text)
- h(truncate_single_line(text, :length => 100))
- end
-
- def format_activity_day(date)
- date == Date.today ? l(:label_today).titleize : format_date(date)
- end
-
- def format_activity_description(text)
- h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, " ")
- end
-
- def format_version_name(version)
- if version.project == @project
- h(version)
- else
- h("#{version.project} - #{version}")
- end
- end
-
- def due_date_distance_in_words(date)
- if date
- l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
- end
- end
-
- def render_page_hierarchy(pages, node=nil, options={})
- content = ''
- if pages[node]
- content << "\n"
- pages[node].each do |page|
- content << ""
- content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title},
- :title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
- content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
- content << " \n"
- end
- content << " \n"
- end
- content.html_safe
- end
-
- # Renders flash messages
- def render_flash_messages
- s = ''
- flash.each do |k,v|
- s << content_tag('div', v, :class => "flash #{k}")
- end
- s.html_safe
- end
-
- # Renders tabs and their content
- def render_tabs(tabs)
- if tabs.any?
- render :partial => 'common/tabs', :locals => {:tabs => tabs}
- else
- content_tag 'p', l(:label_no_data), :class => "nodata"
- end
- end
-
- # Renders the project quick-jump box
- def render_project_jump_box
- return unless User.current.logged?
- projects = User.current.memberships.collect(&:project).compact.uniq
- if projects.any?
- s = '' +
- "#{ l(:label_jump_to_a_project) } " +
- '--- '
- s << project_tree_options_for_select(projects, :selected => @project) do |p|
- { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
- end
- s << ' '
- s.html_safe
- end
- end
-
- def project_tree_options_for_select(projects, options = {})
- s = ''
- project_tree(projects) do |project, level|
- name_prefix = (level > 0 ? (' ' * 2 * level + '» ') : '')
- tag_options = {:value => project.id}
- if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project))
- tag_options[:selected] = 'selected'
- else
- tag_options[:selected] = nil
- end
- tag_options.merge!(yield(project)) if block_given?
- s << content_tag('option', name_prefix + h(project), tag_options)
- end
- s.html_safe
- end
-
- # Yields the given block for each project with its level in the tree
- #
- # Wrapper for Project#project_tree
- def project_tree(projects, &block)
- Project.project_tree(projects, &block)
- end
-
- def project_nested_ul(projects, &block)
- s = ''
- if projects.any?
- ancestors = []
- projects.sort_by(&:lft).each do |project|
- if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
- s << "\n"
- else
- ancestors.pop
- s << ""
- while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
- ancestors.pop
- s << " \n"
- end
- end
- s << ""
- s << yield(project).to_s
- ancestors << project
- end
- s << (" \n" * ancestors.size)
- end
- s.html_safe
- end
-
- def principals_check_box_tags(name, principals)
- s = ''
- principals.sort.each do |principal|
- s << "#{ check_box_tag name, principal.id, false } #{h principal} \n"
- end
- s.html_safe
- end
-
- # Returns a string for users/groups option tags
- def principals_options_for_select(collection, selected=nil)
- s = ''
- groups = ''
- collection.sort.each do |element|
- selected_attribute = ' selected="selected"' if option_value_selected?(element, selected)
- (element.is_a?(Group) ? groups : s) << %(#{h element.name} )
- end
- unless groups.empty?
- s << %(#{groups} )
- end
- s
- end
-
- # Truncates and returns the string as a single line
- def truncate_single_line(string, *args)
- truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
- end
-
- # Truncates at line break after 250 characters or options[:length]
- def truncate_lines(string, options={})
- length = options[:length] || 250
- if string.to_s =~ /\A(.{#{length}}.*?)$/m
- "#{$1}..."
- else
- string
- end
- end
-
- def html_hours(text)
- text.gsub(%r{(\d+)\.(\d+)}, '\1 .\2 ').html_safe
- end
-
- def authoring(created, author, options={})
- l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe
- end
-
- def time_tag(time)
- text = distance_of_time_in_words(Time.now, time)
- if @project
- link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => time.to_date}, :title => format_time(time))
- else
- content_tag('acronym', text, :title => format_time(time))
- end
- end
-
- def syntax_highlight(name, content)
- Redmine::SyntaxHighlighting.highlight_by_filename(content, name)
- end
-
- def to_path_param(path)
- path.to_s.split(%r{[/\\]}).select {|p| !p.blank?}
- end
-
- def pagination_links_full(paginator, count=nil, options={})
- page_param = options.delete(:page_param) || :page
- per_page_links = options.delete(:per_page_links)
- url_param = params.dup
-
- html = ''
- if paginator.current.previous
- # \xc2\xab(utf-8) = «
- html << link_to_content_update(
- "\xc2\xab " + l(:label_previous),
- url_param.merge(page_param => paginator.current.previous)) + ' '
- end
-
- html << (pagination_links_each(paginator, options) do |n|
- link_to_content_update(n.to_s, url_param.merge(page_param => n))
- end || '')
-
- if paginator.current.next
- # \xc2\xbb(utf-8) = »
- html << ' ' + link_to_content_update(
- (l(:label_next) + " \xc2\xbb"),
- url_param.merge(page_param => paginator.current.next))
- end
-
- unless count.nil?
- html << " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})"
- if per_page_links != false && links = per_page_links(paginator.items_per_page)
- html << " | #{links}"
- end
- end
-
- html.html_safe
- end
-
- def per_page_links(selected=nil)
- links = Setting.per_page_options_array.collect do |n|
- n == selected ? n : link_to_content_update(n, params.merge(:per_page => n))
- end
- links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
- end
-
- def reorder_links(name, url, method = :post)
- link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)),
- url.merge({"#{name}[move_to]" => 'highest'}),
- :method => method, :title => l(:label_sort_highest)) +
- link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)),
- url.merge({"#{name}[move_to]" => 'higher'}),
- :method => method, :title => l(:label_sort_higher)) +
- link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)),
- url.merge({"#{name}[move_to]" => 'lower'}),
- :method => method, :title => l(:label_sort_lower)) +
- link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)),
- url.merge({"#{name}[move_to]" => 'lowest'}),
- :method => method, :title => l(:label_sort_lowest))
- end
-
- def breadcrumb(*args)
- elements = args.flatten
- elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil
- end
-
- def other_formats_links(&block)
- concat(''.html_safe + l(:label_export_to))
- yield Redmine::Views::OtherFormatsBuilder.new(self)
- concat('
'.html_safe)
- end
-
- def page_header_title
- if @project.nil? || @project.new_record?
- h(Setting.app_title)
- else
- b = []
- ancestors = (@project.root? ? [] : @project.ancestors.visible.all)
- if ancestors.any?
- root = ancestors.shift
- b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
- if ancestors.size > 2
- b << "\xe2\x80\xa6"
- ancestors = ancestors[-2, 2]
- end
- b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
- end
- b << h(@project)
- b.join(" \xc2\xbb ").html_safe
- end
- end
-
- def html_title(*args)
- if args.empty?
- title = @html_title || []
- title << @project.name if @project
- title << Setting.app_title unless Setting.app_title == title.last
- title.select {|t| !t.blank? }.join(' - ')
- else
- @html_title ||= []
- @html_title += args
- end
- end
-
- # Returns the theme, controller name, and action as css classes for the
- # HTML body.
- def body_css_classes
- css = []
- if theme = Redmine::Themes.theme(Setting.ui_theme)
- css << 'theme-' + theme.name
- end
-
- css << 'controller-' + params[:controller]
- css << 'action-' + params[:action]
- css.join(' ')
- end
-
- def accesskey(s)
- Redmine::AccessKeys.key_for s
- end
-
- # Formats text according to system settings.
- # 2 ways to call this method:
- # * with a String: textilizable(text, options)
- # * with an object and one of its attribute: textilizable(issue, :description, options)
- def textilizable(*args)
- options = args.last.is_a?(Hash) ? args.pop : {}
- case args.size
- when 1
- obj = options[:object]
- text = args.shift
- when 2
- obj = args.shift
- attr = args.shift
- text = obj.send(attr).to_s
- else
- raise ArgumentError, 'invalid arguments to textilizable'
- end
- return '' if text.blank?
- project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
- only_path = options.delete(:only_path) == false ? false : true
-
- text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr)
-
- @parsed_headings = []
- @current_section = 0 if options[:edit_section_links]
- text = parse_non_pre_blocks(text) do |text|
- [:parse_sections, :parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_macros, :parse_headings].each do |method_name|
- send method_name, text, project, obj, attr, only_path, options
- end
- end
-
- if @parsed_headings.any?
- replace_toc(text, @parsed_headings)
- end
-
- text
- end
-
- def parse_non_pre_blocks(text)
- s = StringScanner.new(text)
- tags = []
- parsed = ''
- while !s.eos?
- s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im)
- text, full_tag, closing, tag = s[1], s[2], s[3], s[4]
- if tags.empty?
- yield text
- end
- parsed << text
- if tag
- if closing
- if tags.last == tag.downcase
- tags.pop
- end
- else
- tags << tag.downcase
- end
- parsed << full_tag
- end
- end
- # Close any non closing tags
- while tag = tags.pop
- parsed << "#{tag}>"
- end
- parsed.html_safe
- end
-
- def parse_inline_attachments(text, project, obj, attr, only_path, options)
- # when using an image link, try to use an attachment, if possible
- if options[:attachments] || (obj && obj.respond_to?(:attachments))
- attachments = options[:attachments] || obj.attachments
- text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
- filename, ext, alt, alttext = $1.downcase, $2, $3, $4
- # search for the picture in attachments
- if found = Attachment.latest_attach(attachments, filename)
- image_url = url_for :only_path => only_path, :controller => 'attachments',
- :action => 'download', :id => found
- desc = found.description.to_s.gsub('"', '')
- if !desc.blank? && alttext.blank?
- alt = " title=\"#{desc}\" alt=\"#{desc}\""
- end
- "src=\"#{image_url}\"#{alt}".html_safe
- else
- m.html_safe
- end
- end
- end
- end
-
- # Wiki links
- #
- # Examples:
- # [[mypage]]
- # [[mypage|mytext]]
- # wiki links can refer other project wikis, using project name or identifier:
- # [[project:]] -> wiki starting page
- # [[project:|mytext]]
- # [[project:mypage]]
- # [[project:mypage|mytext]]
- def parse_wiki_links(text, project, obj, attr, only_path, options)
- text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m|
- link_project = project
- esc, all, page, title = $1, $2, $3, $5
- if esc.nil?
- if page =~ /^([^\:]+)\:(.*)$/
- link_project = Project.find_by_identifier($1) || Project.find_by_name($1)
- page = $2
- title ||= $1 if page.blank?
- end
-
- if link_project && link_project.wiki
- # extract anchor
- anchor = nil
- if page =~ /^(.+?)\#(.+)$/
- page, anchor = $1, $2
- end
- anchor = sanitize_anchor_name(anchor) if anchor.present?
- # check if page exists
- wiki_page = link_project.wiki.find_page(page)
- url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page
- "##{anchor}"
- else
- case options[:wiki_links]
- when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '')
- when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export
- else
- wiki_page_id = page.present? ? Wiki.titleize(page) : nil
- url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor)
- end
- end
- link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
- else
- # project or wiki doesn't exist
- all.html_safe
- end
- else
- all.html_safe
- end
- end
- end
-
- # Redmine links
- #
- # Examples:
- # Issues:
- # #52 -> Link to issue #52
- # Changesets:
- # r52 -> Link to revision 52
- # commit:a85130f -> Link to scmid starting with a85130f
- # Documents:
- # document#17 -> Link to document with id 17
- # document:Greetings -> Link to the document with title "Greetings"
- # document:"Some document" -> Link to the document with title "Some document"
- # Versions:
- # version#3 -> Link to version with id 3
- # version:1.0.0 -> Link to version named "1.0.0"
- # version:"1.0 beta 2" -> Link to version named "1.0 beta 2"
- # Attachments:
- # attachment:file.zip -> Link to the attachment of the current object named file.zip
- # Source files:
- # source:some/file -> Link to the file located at /some/file in the project's repository
- # source:some/file@52 -> Link to the file's revision 52
- # source:some/file#L120 -> Link to line 120 of the file
- # source:some/file@52#L120 -> Link to line 120 of the file's revision 52
- # export:some/file -> Force the download of the file
- # Forum messages:
- # message#1218 -> Link to message with id 1218
- #
- # Links can refer other objects from other projects, using project identifier:
- # identifier:r52
- # identifier:document:"Some document"
- # identifier:version:1.0.0
- # identifier:source:some/file
- def parse_redmine_links(text, project, obj, attr, only_path, options)
- text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|forum|news|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m|
- leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10
- link = nil
- if project_identifier
- project = Project.visible.find_by_identifier(project_identifier)
- end
- if esc.nil?
- if prefix.nil? && sep == 'r'
- # project.changesets.visible raises an SQL error because of a double join on repositories
- if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier))
- link = link_to(h("#{project_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
- :class => 'changeset',
- :title => truncate_single_line(changeset.comments, :length => 100))
- end
- elsif sep == '#'
- oid = identifier.to_i
- case prefix
- when nil
- if issue = Issue.visible.find_by_id(oid, :include => :status)
- link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid},
- :class => issue.css_classes,
- :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
- end
- when 'document'
- if document = Document.visible.find_by_id(oid)
- link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
- :class => 'document'
- end
- when 'version'
- if version = Version.visible.find_by_id(oid)
- link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
- :class => 'version'
- end
- when 'message'
- if message = Message.visible.find_by_id(oid, :include => :parent)
- link = link_to_message(message, {:only_path => only_path}, :class => 'message')
- end
- when 'forum'
- if board = Board.visible.find_by_id(oid)
- link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
- :class => 'board'
- end
- when 'news'
- if news = News.visible.find_by_id(oid)
- link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
- :class => 'news'
- end
- when 'project'
- if p = Project.visible.find_by_id(oid)
- link = link_to_project(p, {:only_path => only_path}, :class => 'project')
- end
- end
- elsif sep == ':'
- # removes the double quotes if any
- name = identifier.gsub(%r{^"(.*)"$}, "\\1")
- case prefix
- when 'document'
- if project && document = project.documents.visible.find_by_title(name)
- link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
- :class => 'document'
- end
- when 'version'
- if project && version = project.versions.visible.find_by_name(name)
- link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
- :class => 'version'
- end
- when 'forum'
- if project && board = project.boards.visible.find_by_name(name)
- link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
- :class => 'board'
- end
- when 'news'
- if project && news = project.news.visible.find_by_title(name)
- link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
- :class => 'news'
- end
- when 'commit'
- if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"]))
- link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier},
- :class => 'changeset',
- :title => truncate_single_line(h(changeset.comments), :length => 100)
- end
- when 'source', 'export'
- if project && project.repository && User.current.allowed_to?(:browse_repository, project)
- name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
- path, rev, anchor = $1, $3, $5
- link = link_to h("#{project_prefix}#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
- :path => to_path_param(path),
- :rev => rev,
- :anchor => anchor,
- :format => (prefix == 'export' ? 'raw' : nil)},
- :class => (prefix == 'export' ? 'source download' : 'source')
- end
- when 'attachment'
- attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
- if attachments && attachment = attachments.detect {|a| a.filename == name }
- link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
- :class => 'attachment'
- end
- when 'project'
- if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}])
- link = link_to_project(p, {:only_path => only_path}, :class => 'project')
- end
- end
- end
- end
- (leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")).html_safe
- end
- end
-
- HEADING_RE = /(]+)?>(.+?)<\/h(1|2|3|4)>)/i unless const_defined?(:HEADING_RE)
-
- def parse_sections(text, project, obj, attr, only_path, options)
- return unless options[:edit_section_links]
- text.gsub!(HEADING_RE) do
- @current_section += 1
- if @current_section > 1
- content_tag('div',
- link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)),
- :class => 'contextual',
- :title => l(:button_edit_section)) + $1
- else
- $1
- end
- end
- end
-
- # Headings and TOC
- # Adds ids and links to headings unless options[:headings] is set to false
- def parse_headings(text, project, obj, attr, only_path, options)
- return if options[:headings] == false
-
- text.gsub!(HEADING_RE) do
- level, attrs, content = $2.to_i, $3, $4
- item = strip_tags(content).strip
- anchor = sanitize_anchor_name(item)
- # used for single-file wiki export
- anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version))
- @parsed_headings << [level, anchor, item]
- " \n#{content}¶ "
- end
- end
-
- MACROS_RE = /
- (!)? # escaping
- (
- \{\{ # opening tag
- ([\w]+) # macro name
- (\(([^\}]*)\))? # optional arguments
- \}\} # closing tag
- )
- /x unless const_defined?(:MACROS_RE)
-
- # Macros substitution
- def parse_macros(text, project, obj, attr, only_path, options)
- text.gsub!(MACROS_RE) do
- esc, all, macro = $1, $2, $3.downcase
- args = ($5 || '').split(',').each(&:strip)
- if esc.nil?
- begin
- exec_macro(macro, obj, args)
- rescue => e
- "Error executing the #{macro} macro (#{e})
"
- end || all
- else
- all
- end
- end
- end
-
- TOC_RE = /\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
-
- # Renders the TOC with given headings
- def replace_toc(text, headings)
- text.gsub!(TOC_RE) do
- if headings.empty?
- ''
- else
- div_class = 'toc'
- div_class << ' right' if $1 == '>'
- div_class << ' left' if $1 == '<'
- out = "
"
- root = headings.map(&:first).min
- current = root
- started = false
- headings.each do |level, anchor, item|
- if level > current
- out << '' * (level - current)
- elsif level < current
- out << " \n" * (current - level) + " "
- elsif started
- out << ' '
- end
- out << "#{item} "
- current = level
- started = true
- end
- out << ' ' * (current - root)
- out << ''
- end
- end
- end
-
- # Same as Rails' simple_format helper without using paragraphs
- def simple_format_without_paragraph(text)
- text.to_s.
- gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
- gsub(/\n\n+/, " "). # 2+ newline -> 2 br
- gsub(/([^\n]\n)(?=[^\n])/, '\1 '). # 1 newline -> br
- html_safe
- end
-
- def lang_options_for_select(blank=true)
- (blank ? [["(auto)", ""]] : []) +
- valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last }
- end
-
- def label_tag_for(name, option_tags = nil, options = {})
- label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
- content_tag("label", label_text)
- end
-
- def labelled_tabular_form_for(*args, &proc)
- args << {} unless args.last.is_a?(Hash)
- options = args.last
- options[:html] ||= {}
- options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
- options.merge!({:builder => TabularFormBuilder})
- form_for(*args, &proc)
- end
-
- def labelled_form_for(*args, &proc)
- args << {} unless args.last.is_a?(Hash)
- options = args.last
- options.merge!({:builder => TabularFormBuilder})
- form_for(*args, &proc)
- end
-
- def back_url_hidden_field_tag
- back_url = params[:back_url] || request.env['HTTP_REFERER']
- back_url = CGI.unescape(back_url.to_s)
- hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?
- end
-
- def check_all_links(form_name)
- link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
- " | ".html_safe +
- link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
- end
-
- def progress_bar(pcts, options={})
- pcts = [pcts, pcts] unless pcts.is_a?(Array)
- pcts = pcts.collect(&:round)
- pcts[1] = pcts[1] - pcts[0]
- pcts << (100 - pcts[1] - pcts[0])
- width = options[:width] || '100px;'
- legend = options[:legend] || ''
- content_tag('table',
- content_tag('tr',
- (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) +
- (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) +
- (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe)
- ), :class => 'progress', :style => "width: #{width};").html_safe +
- content_tag('p', legend, :class => 'pourcent').html_safe
- end
-
- def checked_image(checked=true)
- if checked
- image_tag 'toggle_check.png'
- end
- end
-
- def context_menu(url)
- unless @context_menu_included
- content_for :header_tags do
- javascript_include_tag('context_menu') +
- stylesheet_link_tag('context_menu')
- end
- if l(:direction) == 'rtl'
- content_for :header_tags do
- stylesheet_link_tag('context_menu_rtl')
- end
- end
- @context_menu_included = true
- end
- javascript_tag "new ContextMenu('#{ url_for(url) }')"
- end
-
- def context_menu_link(name, url, options={})
- options[:class] ||= ''
- if options.delete(:selected)
- options[:class] << ' icon-checked disabled'
- options[:disabled] = true
- end
- if options.delete(:disabled)
- options.delete(:method)
- options.delete(:confirm)
- options.delete(:onclick)
- options[:class] << ' disabled'
- url = '#'
- end
- link_to h(name), url, options
- end
-
- def calendar_for(field_id)
- include_calendar_headers_tags
- image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
- javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
- end
-
- def include_calendar_headers_tags
- unless @calendar_headers_tags_included
- @calendar_headers_tags_included = true
- content_for :header_tags do
- start_of_week = case Setting.start_of_week.to_i
- when 1
- 'Calendar._FD = 1;' # Monday
- when 7
- 'Calendar._FD = 0;' # Sunday
- when 6
- 'Calendar._FD = 6;' # Saturday
- else
- '' # use language
- end
-
- javascript_include_tag('calendar/calendar') +
- javascript_include_tag("calendar/lang/calendar-#{current_language.to_s.downcase}.js") +
- javascript_tag(start_of_week) +
- javascript_include_tag('calendar/calendar-setup') +
- stylesheet_link_tag('calendar')
- end
- end
- end
-
- def content_for(name, content = nil, &block)
- @has_content ||= {}
- @has_content[name] = true
- super(name, content, &block)
- end
-
- def has_content?(name)
- (@has_content && @has_content[name]) || false
- end
-
- def email_delivery_enabled?
- !!ActionMailer::Base.perform_deliveries
- end
-
- # Returns the avatar image tag for the given +user+ if avatars are enabled
- # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe ')
- def avatar(user, options = { })
- if Setting.gravatar_enabled?
- options.merge!({:ssl => (defined?(request) && request.ssl?), :default => Setting.gravatar_default})
- email = nil
- if user.respond_to?(:mail)
- email = user.mail
- elsif user.to_s =~ %r{<(.+?)>}
- email = $1
- end
- return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil
- else
- ''
- end
- end
-
- def sanitize_anchor_name(anchor)
- anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
- end
-
- # Returns the javascript tags that are included in the html layout head
- def javascript_heads
- tags = javascript_include_tag(:defaults)
- unless User.current.pref.warn_on_leaving_unsaved == '0'
- tags << "\n".html_safe + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });")
- end
- tags
- end
-
- def favicon
- " ".html_safe
- end
-
- def robot_exclusion_tag
- ' '.html_safe
- end
-
- # Returns true if arg is expected in the API response
- def include_in_api_response?(arg)
- unless @included_in_api_response
- param = params[:include]
- @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',')
- @included_in_api_response.collect!(&:strip)
- end
- @included_in_api_response.include?(arg.to_s)
- end
-
- # Returns options or nil if nometa param or X-Redmine-Nometa header
- # was set in the request
- def api_meta(options)
- if params[:nometa].present? || request.headers['X-Redmine-Nometa']
- # compatibility mode for activeresource clients that raise
- # an error when unserializing an array with attributes
- nil
- else
- options
- end
- end
-
- private
-
- def wiki_helper
- helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
- extend helper
- return self
- end
-
- def link_to_content_update(text, url_params = {}, html_options = {})
- link_to(text, url_params, html_options)
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/6d/6d8b57d3f9af4fafe2fd6cde3312b234c4375e61.svn-base
--- a/.svn/pristine/6d/6d8b57d3f9af4fafe2fd6cde3312b234c4375e61.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-class Message < ActiveRecord::Base
- generator_for :subject, :start => 'A Message'
- generator_for :content, :start => 'Some content here'
- generator_for :board, :method => :generate_board
-
- def self.generate_board
- Board.generate!
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/6f/6f1d2fd545f7dc1fe9896fc80a8a9990c3a19370.svn-base
--- a/.svn/pristine/6f/6f1d2fd545f7dc1fe9896fc80a8a9990c3a19370.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require File.expand_path('../../test_helper', __FILE__)
-require 'boards_controller'
-
-# Re-raise errors caught by the controller.
-class BoardsController; def rescue_action(e) raise e end; end
-
-class BoardsControllerTest < ActionController::TestCase
- fixtures :projects, :users, :members, :member_roles, :roles, :boards, :messages, :enabled_modules
-
- def setup
- @controller = BoardsController.new
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
- User.current = nil
- end
-
- def test_index
- get :index, :project_id => 1
- assert_response :success
- assert_template 'index'
- assert_not_nil assigns(:boards)
- assert_not_nil assigns(:project)
- end
-
- def test_index_not_found
- get :index, :project_id => 97
- assert_response 404
- end
-
- def test_index_should_show_messages_if_only_one_board
- Project.find(1).boards.slice(1..-1).each(&:destroy)
-
- get :index, :project_id => 1
- assert_response :success
- assert_template 'show'
- assert_not_nil assigns(:topics)
- end
-
- def test_post_new
- @request.session[:user_id] = 2
- assert_difference 'Board.count' do
- post :new, :project_id => 1, :board => { :name => 'Testing', :description => 'Testing board creation'}
- end
- assert_redirected_to '/projects/ecookbook/settings/boards'
- end
-
- def test_show
- get :show, :project_id => 1, :id => 1
- assert_response :success
- assert_template 'show'
- assert_not_nil assigns(:board)
- assert_not_nil assigns(:project)
- assert_not_nil assigns(:topics)
- end
-
- def test_show_atom
- get :show, :project_id => 1, :id => 1, :format => 'atom'
- assert_response :success
- assert_template 'common/feed.atom'
- assert_not_nil assigns(:board)
- assert_not_nil assigns(:project)
- assert_not_nil assigns(:messages)
- end
-
- def test_post_edit
- @request.session[:user_id] = 2
- assert_no_difference 'Board.count' do
- post :edit, :project_id => 1, :id => 2, :board => { :name => 'Testing', :description => 'Testing board update'}
- end
- assert_redirected_to '/projects/ecookbook/settings/boards'
- assert_equal 'Testing', Board.find(2).name
- end
-
- def test_post_destroy
- @request.session[:user_id] = 2
- assert_difference 'Board.count', -1 do
- post :destroy, :project_id => 1, :id => 2
- end
- assert_redirected_to '/projects/ecookbook/settings/boards'
- assert_nil Board.find_by_id(2)
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/72/7206c2f048a430c2b450227be9a8b2adfead5fc9.svn-base
--- a/.svn/pristine/72/7206c2f048a430c2b450227be9a8b2adfead5fc9.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-module MembersHelper
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/73/7300a4e4784e1a8a94fcf1b6586e7c60896cd357.svn-base
--- a/.svn/pristine/73/7300a4e4784e1a8a94fcf1b6586e7c60896cd357.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class Wiki < ActiveRecord::Base
- belongs_to :project
- has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title'
- has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all
-
- acts_as_watchable
-
- validates_presence_of :start_page
- validates_format_of :start_page, :with => /^[^,\.\/\?\;\|\:]*$/
-
- def visible?(user=User.current)
- !user.nil? && user.allowed_to?(:view_wiki_pages, project)
- end
-
- # Returns the wiki page that acts as the sidebar content
- # or nil if no such page exists
- def sidebar
- @sidebar ||= find_page('Sidebar', :with_redirect => false)
- end
-
- # find the page with the given title
- # if page doesn't exist, return a new page
- def find_or_new_page(title)
- title = start_page if title.blank?
- find_page(title) || WikiPage.new(:wiki => self, :title => Wiki.titleize(title))
- end
-
- # find the page with the given title
- def find_page(title, options = {})
- @page_found_with_redirect = false
- title = start_page if title.blank?
- title = Wiki.titleize(title)
- page = pages.first(:conditions => ["LOWER(title) = LOWER(?)", title])
- if !page && !(options[:with_redirect] == false)
- # search for a redirect
- redirect = redirects.first(:conditions => ["LOWER(title) = LOWER(?)", title])
- if redirect
- page = find_page(redirect.redirects_to, :with_redirect => false)
- @page_found_with_redirect = true
- end
- end
- page
- end
-
- # Returns true if the last page was found with a redirect
- def page_found_with_redirect?
- @page_found_with_redirect
- end
-
- # Finds a page by title
- # The given string can be of one of the forms: "title" or "project:title"
- # Examples:
- # Wiki.find_page("bar", project => foo)
- # Wiki.find_page("foo:bar")
- def self.find_page(title, options = {})
- project = options[:project]
- if title.to_s =~ %r{^([^\:]+)\:(.*)$}
- project_identifier, title = $1, $2
- project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier)
- end
- if project && project.wiki
- page = project.wiki.find_page(title)
- if page && page.content
- page
- end
- end
- end
-
- # turn a string into a valid page title
- def self.titleize(title)
- # replace spaces with _ and remove unwanted caracters
- title = title.gsub(/\s+/, '_').delete(',./?;|:') if title
- # upcase the first letter
- title = (title.slice(0..0).upcase + (title.slice(1..-1) || '')) if title
- title
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/77/77c91510676103db2b08bd0c1bb6738d87279b85.svn-base
--- a/.svn/pristine/77/77c91510676103db2b08bd0c1bb6738d87279b85.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1009 +0,0 @@
-# Italian translations for Ruby on Rails
-# by Claudio Poli (masterkain@gmail.com)
-# by Diego Pierotto (ita.translations@tiscali.it)
-# by Emidio Stani (emidiostani@gmail.com)
-
-it:
- direction: ltr
- date:
- formats:
- default: "%d-%m-%Y"
- short: "%d %b"
- long: "%d %B %Y"
- only_day: "%e"
-
- day_names: [Domenica, Lunedì, Martedì, Mercoledì, Giovedì, Venerdì, Sabato]
- abbr_day_names: [Dom, Lun, Mar, Mer, Gio, Ven, Sab]
- month_names: [~, Gennaio, Febbraio, Marzo, Aprile, Maggio, Giugno, Luglio, Agosto, Settembre, Ottobre, Novembre, Dicembre]
- abbr_month_names: [~, Gen, Feb, Mar, Apr, Mag, Giu, Lug, Ago, Set, Ott, Nov, Dic]
- order:
- - :day
- - :month
- - :year
-
- time:
- formats:
- default: "%a %d %b %Y, %H:%M:%S %z"
- time: "%H:%M"
- short: "%d %b %H:%M"
- long: "%d %B %Y %H:%M"
- only_second: "%S"
-
- datetime:
- formats:
- default: "%d-%m-%YT%H:%M:%S%Z"
-
- am: 'am'
- pm: 'pm'
-
- datetime:
- distance_in_words:
- half_a_minute: "mezzo minuto"
- less_than_x_seconds:
- one: "meno di un secondo"
- other: "meno di %{count} secondi"
- x_seconds:
- one: "1 secondo"
- other: "%{count} secondi"
- less_than_x_minutes:
- one: "meno di un minuto"
- other: "meno di %{count} minuti"
- x_minutes:
- one: "1 minuto"
- other: "%{count} minuti"
- about_x_hours:
- one: "circa un'ora"
- other: "circa %{count} ore"
- x_days:
- one: "1 giorno"
- other: "%{count} giorni"
- about_x_months:
- one: "circa un mese"
- other: "circa %{count} mesi"
- x_months:
- one: "1 mese"
- other: "%{count} mesi"
- about_x_years:
- one: "circa un anno"
- other: "circa %{count} anni"
- over_x_years:
- one: "oltre un anno"
- other: "oltre %{count} anni"
- almost_x_years:
- one: "quasi 1 anno"
- other: "quasi %{count} anni"
-
- number:
- format:
- precision: 3
- separator: ','
- delimiter: '.'
- currency:
- format:
- unit: '€'
- precision: 2
- format: '%n %u'
- human:
- storage_units:
- format: "%n %u"
- units:
- byte:
- one: "Byte"
- other: "Bytes"
- kb: "KB"
- mb: "MB"
- gb: "GB"
- tb: "TB"
-
- support:
- array:
- sentence_connector: "e"
- skip_last_comma: false
-
- activerecord:
- errors:
- template:
- header:
- one: "Non posso salvare questo %{model}: 1 errore"
- other: "Non posso salvare questo %{model}: %{count} errori."
- body: "Per favore ricontrolla i seguenti campi:"
- messages:
- inclusion: "non è incluso nella lista"
- exclusion: "è riservato"
- invalid: "non è valido"
- confirmation: "non coincide con la conferma"
- accepted: "deve essere accettata"
- empty: "non può essere vuoto"
- blank: "non può essere lasciato in bianco"
- too_long: "è troppo lungo (il massimo è %{count} lettere)"
- too_short: "è troppo corto (il minimo è %{count} lettere)"
- wrong_length: "è della lunghezza sbagliata (deve essere di %{count} lettere)"
- taken: "è già in uso"
- not_a_number: "non è un numero"
- greater_than: "deve essere superiore a %{count}"
- greater_than_or_equal_to: "deve essere superiore o uguale a %{count}"
- equal_to: "deve essere uguale a %{count}"
- less_than: "deve essere meno di %{count}"
- less_than_or_equal_to: "deve essere meno o uguale a %{count}"
- odd: "deve essere dispari"
- even: "deve essere pari"
- greater_than_start_date: "deve essere maggiore della data di partenza"
- not_same_project: "non appartiene allo stesso progetto"
- circular_dependency: "Questa relazione creerebbe una dipendenza circolare"
- cant_link_an_issue_with_a_descendant: "Una segnalazione non può essere collegata a una delle sue discendenti"
-
- actionview_instancetag_blank_option: Scegli
-
- general_text_No: 'No'
- general_text_Yes: 'Sì'
- general_text_no: 'no'
- general_text_yes: 'sì'
- general_lang_name: 'Italiano'
- general_csv_separator: ';'
- general_csv_decimal_separator: ','
- general_csv_encoding: ISO-8859-1
- general_pdf_encoding: UTF-8
- general_first_day_of_week: '1'
-
- notice_account_updated: L'utente è stato aggiornato.
- notice_account_invalid_creditentials: Nome utente o password non validi.
- notice_account_password_updated: La password è stata aggiornata.
- notice_account_wrong_password: Password errata
- notice_account_register_done: L'utente è stato creato.
- notice_account_unknown_email: Utente sconosciuto.
- notice_can_t_change_password: Questo utente utilizza un metodo di autenticazione esterno. Impossibile cambiare la password.
- notice_account_lost_email_sent: Ti è stata spedita una email con le istruzioni per cambiare la password.
- notice_account_activated: Il tuo account è stato attivato. Ora puoi effettuare l'accesso.
- notice_successful_create: Creazione effettuata.
- notice_successful_update: Modifica effettuata.
- notice_successful_delete: Eliminazione effettuata.
- notice_successful_connection: Connessione effettuata.
- notice_file_not_found: La pagina desiderata non esiste o è stata rimossa.
- notice_locking_conflict: Le informazioni sono state modificate da un altro utente.
- notice_not_authorized: Non sei autorizzato ad accedere a questa pagina.
- notice_email_sent: "Una email è stata spedita a %{value}"
- notice_email_error: "Si è verificato un errore durante l'invio di una email (%{value})"
- notice_feeds_access_key_reseted: La tua chiave di accesso RSS è stata reimpostata.
-
- error_scm_not_found: "La risorsa e/o la versione non esistono nel repository."
- error_scm_command_failed: "Si è verificato un errore durante l'accesso al repository: %{value}"
-
- mail_subject_lost_password: "Password %{value}"
- mail_body_lost_password: 'Per cambiare la password, usa il seguente collegamento:'
- mail_subject_register: "Attivazione utente %{value}"
- mail_body_register: "Per attivare l'utente, usa il seguente collegamento:"
-
- gui_validation_error: 1 errore
- gui_validation_error_plural: "%{count} errori"
-
- field_name: Nome
- field_description: Descrizione
- field_summary: Sommario
- field_is_required: Richiesto
- field_firstname: Nome
- field_lastname: Cognome
- field_mail: Email
- field_filename: File
- field_filesize: Dimensione
- field_downloads: Download
- field_author: Autore
- field_created_on: Creato
- field_updated_on: Aggiornato
- field_field_format: Formato
- field_is_for_all: Per tutti i progetti
- field_possible_values: Valori possibili
- field_regexp: Espressione regolare
- field_min_length: Lunghezza minima
- field_max_length: Lunghezza massima
- field_value: Valore
- field_category: Categoria
- field_title: Titolo
- field_project: Progetto
- field_issue: Segnalazione
- field_status: Stato
- field_notes: Note
- field_is_closed: Chiudi la segnalazione
- field_is_default: Stato predefinito
- field_tracker: Tracker
- field_subject: Oggetto
- field_due_date: Scadenza
- field_assigned_to: Assegnato a
- field_priority: PrioritÃ
- field_fixed_version: Versione prevista
- field_user: Utente
- field_role: Ruolo
- field_homepage: Homepage
- field_is_public: Pubblico
- field_parent: Sottoprogetto di
- field_is_in_roadmap: Segnalazioni mostrate nella roadmap
- field_login: Utente
- field_mail_notification: Notifiche via email
- field_admin: Amministratore
- field_last_login_on: Ultima connessione
- field_language: Lingua
- field_effective_date: Data
- field_password: Password
- field_new_password: Nuova password
- field_password_confirmation: Conferma
- field_version: Versione
- field_type: Tipo
- field_host: Host
- field_port: Porta
- field_account: Utente
- field_base_dn: DN base
- field_attr_login: Attributo connessione
- field_attr_firstname: Attributo nome
- field_attr_lastname: Attributo cognome
- field_attr_mail: Attributo email
- field_onthefly: Creazione utente "al volo"
- field_start_date: Inizio
- field_done_ratio: "% completato"
- field_auth_source: Modalità di autenticazione
- field_hide_mail: Nascondi il mio indirizzo email
- field_comments: Commento
- field_url: URL
- field_start_page: Pagina principale
- field_subproject: Sottoprogetto
- field_hours: Ore
- field_activity: AttivitÃ
- field_spent_on: Data
- field_identifier: Identificativo
- field_is_filter: Usato come filtro
- field_issue_to: Segnalazioni correlate
- field_delay: Ritardo
- field_assignable: E' possibile assegnare segnalazioni a questo ruolo
- field_redirect_existing_links: Redirige i collegamenti esistenti
- field_estimated_hours: Tempo stimato
- field_default_value: Stato predefinito
-
- setting_app_title: Titolo applicazione
- setting_app_subtitle: Sottotitolo applicazione
- setting_welcome_text: Testo di benvenuto
- setting_default_language: Lingua predefinita
- setting_login_required: Autenticazione richiesta
- setting_self_registration: Auto-registrazione abilitata
- setting_attachment_max_size: Dimensione massima allegati
- setting_issues_export_limit: Limite esportazione segnalazioni
- setting_mail_from: Indirizzo sorgente email
- setting_host_name: Nome host
- setting_text_formatting: Formattazione testo
- setting_wiki_compression: Comprimi cronologia wiki
- setting_feeds_limit: Limite contenuti del feed
- setting_autofetch_changesets: Acquisisci automaticamente le commit
- setting_sys_api_enabled: Abilita WS per la gestione del repository
- setting_commit_ref_keywords: Parole chiave riferimento
- setting_commit_fix_keywords: Parole chiave chiusura
- setting_autologin: Connessione automatica
- setting_date_format: Formato data
- setting_cross_project_issue_relations: Consenti la creazione di relazioni tra segnalazioni in progetti differenti
-
- label_user: Utente
- label_user_plural: Utenti
- label_user_new: Nuovo utente
- label_project: Progetto
- label_project_new: Nuovo progetto
- label_project_plural: Progetti
- label_x_projects:
- zero: nessun progetto
- one: 1 progetto
- other: "%{count} progetti"
- label_project_all: Tutti i progetti
- label_project_latest: Ultimi progetti registrati
- label_issue: Segnalazione
- label_issue_new: Nuova segnalazione
- label_issue_plural: Segnalazioni
- label_issue_view_all: Mostra tutte le segnalazioni
- label_document: Documento
- label_document_new: Nuovo documento
- label_document_plural: Documenti
- label_role: Ruolo
- label_role_plural: Ruoli
- label_role_new: Nuovo ruolo
- label_role_and_permissions: Ruoli e permessi
- label_member: Membro
- label_member_new: Nuovo membro
- label_member_plural: Membri
- label_tracker: Tracker
- label_tracker_plural: Tracker
- label_tracker_new: Nuovo tracker
- label_workflow: Workflow
- label_issue_status: Stato segnalazione
- label_issue_status_plural: Stati segnalazioni
- label_issue_status_new: Nuovo stato
- label_issue_category: Categoria segnalazione
- label_issue_category_plural: Categorie segnalazioni
- label_issue_category_new: Nuova categoria
- label_custom_field: Campo personalizzato
- label_custom_field_plural: Campi personalizzati
- label_custom_field_new: Nuovo campo personalizzato
- label_enumerations: Enumerazioni
- label_enumeration_new: Nuovo valore
- label_information: Informazione
- label_information_plural: Informazioni
- label_please_login: Entra
- label_register: Registrati
- label_password_lost: Password dimenticata
- label_home: Home
- label_my_page: Pagina personale
- label_my_account: Il mio utente
- label_my_projects: I miei progetti
- label_administration: Amministrazione
- label_login: Entra
- label_logout: Esci
- label_help: Aiuto
- label_reported_issues: Segnalazioni
- label_assigned_to_me_issues: Le mie segnalazioni
- label_last_login: Ultimo collegamento
- label_registered_on: Registrato il
- label_activity: AttivitÃ
- label_new: Nuovo
- label_logged_as: Collegato come
- label_environment: Ambiente
- label_authentication: Autenticazione
- label_auth_source: Modalità di autenticazione
- label_auth_source_new: Nuova modalità di autenticazione
- label_auth_source_plural: Modalità di autenticazione
- label_subproject_plural: Sottoprogetti
- label_min_max_length: Lunghezza minima - massima
- label_list: Elenco
- label_date: Data
- label_integer: Intero
- label_boolean: Booleano
- label_string: Testo
- label_text: Testo esteso
- label_attribute: Attributo
- label_attribute_plural: Attributi
- label_download: "%{count} Download"
- label_download_plural: "%{count} Download"
- label_no_data: Nessun dato disponibile
- label_change_status: Cambia stato
- label_history: Cronologia
- label_attachment: File
- label_attachment_new: Nuovo file
- label_attachment_delete: Elimina file
- label_attachment_plural: File
- label_report: Report
- label_report_plural: Report
- label_news: Notizia
- label_news_new: Aggiungi notizia
- label_news_plural: Notizie
- label_news_latest: Utime notizie
- label_news_view_all: Tutte le notizie
- label_settings: Impostazioni
- label_overview: Panoramica
- label_version: Versione
- label_version_new: Nuova versione
- label_version_plural: Versioni
- label_confirmation: Conferma
- label_export_to: Esporta su
- label_read: Leggi...
- label_public_projects: Progetti pubblici
- label_open_issues: aperta
- label_open_issues_plural: aperte
- label_closed_issues: chiusa
- label_closed_issues_plural: chiuse
- label_x_open_issues_abbr_on_total:
- zero: 0 aperte / %{total}
- one: 1 aperta / %{total}
- other: "%{count} aperte / %{total}"
- label_x_open_issues_abbr:
- zero: 0 aperte
- one: 1 aperta
- other: "%{count} aperte"
- label_x_closed_issues_abbr:
- zero: 0 chiuse
- one: 1 chiusa
- other: "%{count} chiuse"
- label_total: Totale
- label_permissions: Permessi
- label_current_status: Stato attuale
- label_new_statuses_allowed: Nuovi stati possibili
- label_all: tutti
- label_none: nessuno
- label_next: Successivo
- label_previous: Precedente
- label_used_by: Usato da
- label_details: Dettagli
- label_add_note: Aggiungi una nota
- label_per_page: Per pagina
- label_calendar: Calendario
- label_months_from: mesi da
- label_gantt: Gantt
- label_internal: Interno
- label_last_changes: "ultime %{count} modifiche"
- label_change_view_all: Tutte le modifiche
- label_personalize_page: Personalizza la pagina
- label_comment: Commento
- label_comment_plural: Commenti
- label_x_comments:
- zero: nessun commento
- one: 1 commento
- other: "%{count} commenti"
- label_comment_add: Aggiungi un commento
- label_comment_added: Commento aggiunto
- label_comment_delete: Elimina commenti
- label_query: Query personalizzata
- label_query_plural: Query personalizzate
- label_query_new: Nuova query
- label_filter_add: Aggiungi filtro
- label_filter_plural: Filtri
- label_equals: è
- label_not_equals: non è
- label_in_less_than: è minore di
- label_in_more_than: è maggiore di
- label_in: in
- label_today: oggi
- label_this_week: questa settimana
- label_less_than_ago: meno di giorni fa
- label_more_than_ago: più di giorni fa
- label_ago: giorni fa
- label_contains: contiene
- label_not_contains: non contiene
- label_day_plural: giorni
- label_repository: Repository
- label_browse: Sfoglia
- label_modification: "%{count} modifica"
- label_modification_plural: "%{count} modifiche"
- label_revision: Versione
- label_revision_plural: Versioni
- label_added: aggiunto
- label_modified: modificato
- label_deleted: eliminato
- label_latest_revision: Ultima versione
- label_latest_revision_plural: Ultime versioni
- label_view_revisions: Mostra versioni
- label_max_size: Dimensione massima
- label_sort_highest: Sposta in cima
- label_sort_higher: Su
- label_sort_lower: Giù
- label_sort_lowest: Sposta in fondo
- label_roadmap: Roadmap
- label_roadmap_due_in: "Da ultimare in %{value}"
- label_roadmap_overdue: "%{value} di ritardo"
- label_roadmap_no_issues: Nessuna segnalazione per questa versione
- label_search: Ricerca
- label_result_plural: Risultati
- label_all_words: Tutte le parole
- label_wiki: Wiki
- label_wiki_edit: Modifica wiki
- label_wiki_edit_plural: Modifiche wiki
- label_wiki_page: Pagina Wiki
- label_wiki_page_plural: Pagine wiki
- label_index_by_title: Ordina per titolo
- label_index_by_date: Ordina per data
- label_current_version: Versione corrente
- label_preview: Anteprima
- label_feed_plural: Feed
- label_changes_details: Particolari di tutti i cambiamenti
- label_issue_tracking: Tracking delle segnalazioni
- label_spent_time: Tempo impiegato
- label_f_hour: "%{value} ora"
- label_f_hour_plural: "%{value} ore"
- label_time_tracking: Tracking del tempo
- label_change_plural: Modifiche
- label_statistics: Statistiche
- label_commits_per_month: Commit per mese
- label_commits_per_author: Commit per autore
- label_view_diff: mostra differenze
- label_diff_inline: in linea
- label_diff_side_by_side: fianco a fianco
- label_options: Opzioni
- label_copy_workflow_from: Copia workflow da
- label_permissions_report: Report permessi
- label_watched_issues: Segnalazioni osservate
- label_related_issues: Segnalazioni correlate
- label_applied_status: Stato applicato
- label_loading: Caricamento...
- label_relation_new: Nuova relazione
- label_relation_delete: Elimina relazione
- label_relates_to: correlato a
- label_duplicates: duplicati
- label_blocks: blocchi
- label_blocked_by: bloccato da
- label_precedes: precede
- label_follows: segue
- label_end_to_start: fine a inizio
- label_end_to_end: fine a fine
- label_start_to_start: inizio a inizio
- label_start_to_end: inizio a fine
- label_stay_logged_in: Rimani collegato
- label_disabled: disabilitato
- label_show_completed_versions: Mostra versioni completate
- label_me: me
- label_board: Forum
- label_board_new: Nuovo forum
- label_board_plural: Forum
- label_topic_plural: Argomenti
- label_message_plural: Messaggi
- label_message_last: Ultimo messaggio
- label_message_new: Nuovo messaggio
- label_reply_plural: Risposte
- label_send_information: Invia all'utente le informazioni relative all'account
- label_year: Anno
- label_month: Mese
- label_week: Settimana
- label_date_from: Da
- label_date_to: A
- label_language_based: Basato sul linguaggio
- label_sort_by: "Ordina per %{value}"
- label_send_test_email: Invia una email di prova
- label_feeds_access_key_created_on: "chiave di accesso RSS creata %{value} fa"
- label_module_plural: Moduli
- label_added_time_by: "Aggiunto da %{author} %{age} fa"
- label_updated_time: "Aggiornato %{value} fa"
- label_jump_to_a_project: Vai al progetto...
-
- button_login: Entra
- button_submit: Invia
- button_save: Salva
- button_check_all: Seleziona tutti
- button_uncheck_all: Deseleziona tutti
- button_delete: Elimina
- button_create: Crea
- button_test: Prova
- button_edit: Modifica
- button_add: Aggiungi
- button_change: Cambia
- button_apply: Applica
- button_clear: Pulisci
- button_lock: Blocca
- button_unlock: Sblocca
- button_download: Scarica
- button_list: Elenca
- button_view: Mostra
- button_move: Sposta
- button_back: Indietro
- button_cancel: Annulla
- button_activate: Attiva
- button_sort: Ordina
- button_log_time: Registra tempo
- button_rollback: Ripristina questa versione
- button_watch: Osserva
- button_unwatch: Dimentica
- button_reply: Rispondi
- button_archive: Archivia
- button_unarchive: Ripristina
- button_reset: Reimposta
- button_rename: Rinomina
-
- status_active: attivo
- status_registered: registrato
- status_locked: bloccato
-
- text_select_mail_notifications: Seleziona le azioni per cui deve essere inviata una notifica.
- text_regexp_info: es. ^[A-Z0-9]+$
- text_min_max_length_info: 0 significa nessuna restrizione
- text_project_destroy_confirmation: Sei sicuro di voler eliminare il progetto e tutti i dati ad esso collegati?
- text_workflow_edit: Seleziona un ruolo ed un tracker per modificare il workflow
- text_are_you_sure: Sei sicuro ?
- text_tip_issue_begin_day: attività che iniziano in questa giornata
- text_tip_issue_end_day: attività che terminano in questa giornata
- text_tip_issue_begin_end_day: attività che iniziano e terminano in questa giornata
- text_project_identifier_info: "Lettere minuscole (a-z), numeri e trattini permessi. Una volta salvato, l'identificativo non può essere modificato."
- text_caracters_maximum: "massimo %{count} caratteri."
- text_length_between: "Lunghezza compresa tra %{min} e %{max} caratteri."
- text_tracker_no_workflow: Nessun workflow definito per questo tracker
- text_unallowed_characters: Caratteri non permessi
- text_comma_separated: Valori multipli permessi (separati da virgole).
- text_issues_ref_in_commit_messages: Segnalazioni di riferimento e chiusura nei messaggi di commit
- text_issue_added: "E' stata segnalata l'anomalia %{id} da %{author}."
- text_issue_updated: "L'anomalia %{id} è stata aggiornata da %{author}."
- text_wiki_destroy_confirmation: Sicuro di voler eliminare questo wiki e tutti i suoi contenuti?
- text_issue_category_destroy_question: "Alcune segnalazioni (%{count}) risultano assegnate a questa categoria. Cosa vuoi fare ?"
- text_issue_category_destroy_assignments: Rimuovi le assegnazioni a questa categoria
- text_issue_category_reassign_to: Riassegna segnalazioni a questa categoria
-
- default_role_manager: Gestore
- default_role_developer: Sviluppatore
- default_role_reporter: Segnalatore
- default_tracker_bug: Segnalazione
- default_tracker_feature: Funzione
- default_tracker_support: Supporto
- default_issue_status_new: Nuovo
- default_issue_status_in_progress: In elaborazione
- default_issue_status_resolved: Risolto
- default_issue_status_feedback: Commenti
- default_issue_status_closed: Chiuso
- default_issue_status_rejected: Rifiutato
- default_doc_category_user: Documentazione utente
- default_doc_category_tech: Documentazione tecnica
- default_priority_low: Bassa
- default_priority_normal: Normale
- default_priority_high: Alta
- default_priority_urgent: Urgente
- default_priority_immediate: Immediata
- default_activity_design: Progettazione
- default_activity_development: Sviluppo
-
- enumeration_issue_priorities: Priorità segnalazioni
- enumeration_doc_categories: Categorie di documenti
- enumeration_activities: Attività (time tracking)
- label_file_plural: File
- label_changeset_plural: Changeset
- field_column_names: Colonne
- label_default_columns: Colonne predefinite
- setting_issue_list_default_columns: Colonne predefinite mostrate nell'elenco segnalazioni
- notice_no_issue_selected: "Nessuna segnalazione selezionata! Seleziona le segnalazioni che intendi modificare."
- label_bulk_edit_selected_issues: Modifica massiva delle segnalazioni selezionate
- label_no_change_option: (Nessuna modifica)
- notice_failed_to_save_issues: "Impossibile salvare %{count} segnalazioni su %{total} selezionate: %{ids}."
- label_theme: Tema
- label_default: Predefinito
- label_search_titles_only: Cerca solo nei titoli
- label_nobody: nessuno
- button_change_password: Modifica password
- text_user_mail_option: "Per i progetti non selezionati, riceverai solo le notifiche riguardanti le cose che osservi o nelle quali sei coinvolto (per esempio segnalazioni che hai creato o che ti sono state assegnate)."
- label_user_mail_option_selected: "Solo per gli eventi relativi ai progetti selezionati..."
- label_user_mail_option_all: "Per ogni evento relativo ad uno dei miei progetti"
- setting_emails_footer: Piè di pagina email
- label_float: Decimale
- button_copy: Copia
- mail_body_account_information_external: "Puoi utilizzare il tuo account %{value} per accedere al sistema."
- mail_body_account_information: Le informazioni riguardanti il tuo account
- setting_protocol: Protocollo
- label_user_mail_no_self_notified: "Non voglio notifiche riguardanti modifiche da me apportate"
- setting_time_format: Formato ora
- label_registration_activation_by_email: attivazione account via email
- mail_subject_account_activation_request: "%{value} richiesta attivazione account"
- mail_body_account_activation_request: "Un nuovo utente (%{value}) ha effettuato la registrazione. Il suo account è in attesa di abilitazione da parte tua:"
- label_registration_automatic_activation: attivazione account automatica
- label_registration_manual_activation: attivazione account manuale
- notice_account_pending: "Il tuo account è stato creato ed è in attesa di attivazione da parte dell'amministratore."
- field_time_zone: Fuso orario
- text_caracters_minimum: "Deve essere lungo almeno %{count} caratteri."
- setting_bcc_recipients: Destinatari in copia nascosta (bcc)
- button_annotate: Annota
- label_issues_by: "Segnalazioni di %{value}"
- field_searchable: Ricercabile
- label_display_per_page: "Per pagina: %{value}"
- setting_per_page_options: Opzioni oggetti per pagina
- label_age: EtÃ
- notice_default_data_loaded: Configurazione predefinita caricata con successo.
- text_load_default_configuration: Carica la configurazione predefinita
- text_no_configuration_data: "Ruoli, tracker, stati delle segnalazioni e workflow non sono stati ancora configurati.\nE' vivamente consigliato caricare la configurazione predefinita. Potrai modificarla una volta caricata."
- error_can_t_load_default_data: "Non è stato possibile caricare la configurazione predefinita : %{value}"
- button_update: Aggiorna
- label_change_properties: Modifica le proprietÃ
- label_general: Generale
- label_repository_plural: Repository
- label_associated_revisions: Revisioni associate
- setting_user_format: Formato visualizzazione utenti
- text_status_changed_by_changeset: "Applicata nel changeset %{value}."
- label_more: Altro
- text_issues_destroy_confirmation: 'Sei sicuro di voler eliminare le segnalazioni selezionate?'
- label_scm: SCM
- text_select_project_modules: 'Seleziona i moduli abilitati per questo progetto:'
- label_issue_added: Segnalazioni aggiunte
- label_issue_updated: Segnalazioni aggiornate
- label_document_added: Documenti aggiunti
- label_message_posted: Messaggi aggiunti
- label_file_added: File aggiunti
- label_news_added: Notizie aggiunte
- project_module_boards: Forum
- project_module_issue_tracking: Tracking delle segnalazioni
- project_module_wiki: Wiki
- project_module_files: File
- project_module_documents: Documenti
- project_module_repository: Repository
- project_module_news: Notizie
- project_module_time_tracking: Time tracking
- text_file_repository_writable: Repository dei file scrivibile
- text_default_administrator_account_changed: L'account amministrativo predefinito è stato modificato
- text_rmagick_available: RMagick disponibile (opzionale)
- button_configure: Configura
- label_plugins: Plugin
- label_ldap_authentication: Autenticazione LDAP
- label_downloads_abbr: D/L
- label_this_month: questo mese
- label_last_n_days: "ultimi %{count} giorni"
- label_all_time: sempre
- label_this_year: quest'anno
- label_date_range: Intervallo di date
- label_last_week: ultima settimana
- label_yesterday: ieri
- label_last_month: ultimo mese
- label_add_another_file: Aggiungi un altro file
- label_optional_description: Descrizione opzionale
- text_destroy_time_entries_question: "%{hours} ore risultano spese sulle segnalazioni che stai per eliminare. Cosa vuoi fare ?"
- error_issue_not_found_in_project: 'La segnalazione non è stata trovata o non appartiene al progetto'
- text_assign_time_entries_to_project: Assegna le ore segnalate al progetto
- text_destroy_time_entries: Elimina le ore segnalate
- text_reassign_time_entries: 'Riassegna le ore a questa segnalazione:'
- setting_activity_days_default: Giorni mostrati sulle attività di progetto
- label_chronological_order: In ordine cronologico
- field_comments_sorting: Mostra commenti
- label_reverse_chronological_order: In ordine cronologico inverso
- label_preferences: Preferenze
- setting_display_subprojects_issues: Mostra le segnalazioni dei sottoprogetti nel progetto principale in modo predefinito
- label_overall_activity: Attività generale
- setting_default_projects_public: I nuovi progetti sono pubblici in modo predefinito
- error_scm_annotate: "L'oggetto non esiste o non può essere annotato."
- label_planning: Pianificazione
- text_subprojects_destroy_warning: "Anche i suoi sottoprogetti: %{value} verranno eliminati."
- label_and_its_subprojects: "%{value} ed i suoi sottoprogetti"
- mail_body_reminder: "%{count} segnalazioni che ti sono state assegnate scadranno nei prossimi %{days} giorni:"
- mail_subject_reminder: "%{count} segnalazioni in scadenza nei prossimi %{days} giorni"
- text_user_wrote: "%{value} ha scritto:"
- label_duplicated_by: duplicato da
- setting_enabled_scm: SCM abilitato
- text_enumeration_category_reassign_to: 'Riassegnale a questo valore:'
- text_enumeration_destroy_question: "%{count} oggetti hanno un assegnamento su questo valore."
- label_incoming_emails: Email in arrivo
- label_generate_key: Genera una chiave
- setting_mail_handler_api_enabled: Abilita WS per le email in arrivo
- setting_mail_handler_api_key: Chiave API
- text_email_delivery_not_configured: "La consegna via email non è configurata e le notifiche sono disabilitate.\nConfigura il tuo server SMTP in config/configuration.yml e riavvia l'applicazione per abilitarle."
- field_parent_title: Pagina principale
- label_issue_watchers: Osservatori
- button_quote: Quota
- setting_sequential_project_identifiers: Genera progetti con identificativi in sequenza
- notice_unable_delete_version: Impossibile eliminare la versione
- label_renamed: rinominato
- label_copied: copiato
- setting_plain_text_mail: Solo testo (non HTML)
- permission_view_files: Vedi files
- permission_edit_issues: Modifica segnalazioni
- permission_edit_own_time_entries: Modifica propri time logs
- permission_manage_public_queries: Gestisci query pubbliche
- permission_add_issues: Aggiungi segnalazioni
- permission_log_time: Segna tempo impiegato
- permission_view_changesets: Vedi changesets
- permission_view_time_entries: Vedi tempi impiegati
- permission_manage_versions: Gestisci versioni
- permission_manage_wiki: Gestisci wiki
- permission_manage_categories: Gestisci categorie segnalazioni
- permission_protect_wiki_pages: Proteggi pagine wiki
- permission_comment_news: Commenta notizie
- permission_delete_messages: Elimina messaggi
- permission_select_project_modules: Seleziona moduli progetto
- permission_manage_documents: Gestisci documenti
- permission_edit_wiki_pages: Modifica pagine wiki
- permission_add_issue_watchers: Aggiungi osservatori
- permission_view_gantt: Vedi diagrammi gantt
- permission_move_issues: Muovi segnalazioni
- permission_manage_issue_relations: Gestisci relazioni tra segnalazioni
- permission_delete_wiki_pages: Elimina pagine wiki
- permission_manage_boards: Gestisci forum
- permission_delete_wiki_pages_attachments: Elimina allegati
- permission_view_wiki_edits: Vedi cronologia wiki
- permission_add_messages: Aggiungi messaggi
- permission_view_messages: Vedi messaggi
- permission_manage_files: Gestisci files
- permission_edit_issue_notes: Modifica note
- permission_manage_news: Gestisci notizie
- permission_view_calendar: Vedi calendario
- permission_manage_members: Gestisci membri
- permission_edit_messages: Modifica messaggi
- permission_delete_issues: Elimina segnalazioni
- permission_view_issue_watchers: Vedi lista osservatori
- permission_manage_repository: Gestisci repository
- permission_commit_access: Permesso di commit
- permission_browse_repository: Sfoglia repository
- permission_view_documents: Vedi documenti
- permission_edit_project: Modifica progetti
- permission_add_issue_notes: Aggiungi note
- permission_save_queries: Salva query
- permission_view_wiki_pages: Vedi pagine wiki
- permission_rename_wiki_pages: Rinomina pagine wiki
- permission_edit_time_entries: Modifica time logs
- permission_edit_own_issue_notes: Modifica proprie note
- setting_gravatar_enabled: Usa icone utente Gravatar
- label_example: Esempio
- text_repository_usernames_mapping: "Seleziona per aggiornare la corrispondenza tra gli utenti Redmine e quelli presenti nel log del repository.\nGli utenti Redmine e repository con lo stesso note utente o email sono mappati automaticamente."
- permission_edit_own_messages: Modifica propri messaggi
- permission_delete_own_messages: Elimina propri messaggi
- label_user_activity: "attività di %{value}"
- label_updated_time_by: "Aggiornato da %{author} %{age} fa"
- text_diff_truncated: '... Le differenze sono state troncate perchè superano il limite massimo visualizzabile.'
- setting_diff_max_lines_displayed: Limite massimo di differenze (linee) mostrate
- text_plugin_assets_writable: Directory attività dei plugins scrivibile
- warning_attachments_not_saved: "%{count} file non possono essere salvati."
- button_create_and_continue: Crea e continua
- text_custom_field_possible_values_info: 'Un valore per ogni riga'
- label_display: Mostra
- field_editable: Modificabile
- setting_repository_log_display_limit: Numero massimo di revisioni elencate nella cronologia file
- setting_file_max_size_displayed: Dimensione massima dei contenuti testuali visualizzati
- field_watcher: Osservatore
- setting_openid: Accetta connessione e registrazione con OpenID
- field_identity_url: URL OpenID
- label_login_with_open_id_option: oppure autenticati usando OpenID
- field_content: Contenuto
- label_descending: Discendente
- label_sort: Ordina
- label_ascending: Ascendente
- label_date_from_to: Da %{start} a %{end}
- label_greater_or_equal: ">="
- label_less_or_equal: <=
- text_wiki_page_destroy_question: Questa pagina ha %{descendants} pagine figlie. Cosa ne vuoi fare?
- text_wiki_page_reassign_children: Riassegna le pagine figlie al padre di questa pagina
- text_wiki_page_nullify_children: Mantieni le pagine figlie come pagine radice
- text_wiki_page_destroy_children: Elimina le pagine figlie e tutta la discendenza
- setting_password_min_length: Lunghezza minima password
- field_group_by: Raggruppa risultati per
- mail_subject_wiki_content_updated: "La pagina wiki '%{id}' è stata aggiornata"
- label_wiki_content_added: Aggiunta pagina al wiki
- mail_subject_wiki_content_added: "La pagina '%{id}' è stata aggiunta al wiki"
- mail_body_wiki_content_added: La pagina '%{id}' è stata aggiunta al wiki da %{author}.
- label_wiki_content_updated: Aggiornata pagina wiki
- mail_body_wiki_content_updated: La pagina '%{id}' wiki è stata aggiornata da%{author}.
- permission_add_project: Crea progetto
- setting_new_project_user_role_id: Ruolo assegnato agli utenti non amministratori che creano un progetto
- label_view_all_revisions: Mostra tutte le revisioni
- label_tag: Tag
- label_branch: Branch
- error_no_tracker_in_project: Nessun tracker è associato a questo progetto. Per favore verifica le impostazioni del Progetto.
- error_no_default_issue_status: Nessuno stato predefinito delle segnalazioni è configurato. Per favore verifica le impostazioni (Vai in "Amministrazione -> Stati segnalazioni").
- text_journal_changed: "%{label} modificata da %{old} a %{new}"
- text_journal_set_to: "%{label} impostata a %{value}"
- text_journal_deleted: "%{label} eliminata (%{old})"
- label_group_plural: Gruppi
- label_group: Gruppo
- label_group_new: Nuovo gruppo
- label_time_entry_plural: Tempo impiegato
- text_journal_added: "%{value} %{label} aggiunto"
- field_active: Attivo
- enumeration_system_activity: Attività di sistema
- permission_delete_issue_watchers: Elimina osservatori
- version_status_closed: chiusa
- version_status_locked: bloccata
- version_status_open: aperta
- error_can_not_reopen_issue_on_closed_version: Una segnalazione assegnata ad una versione chiusa non può essere riaperta
- label_user_anonymous: Anonimo
- button_move_and_follow: Sposta e segui
- setting_default_projects_modules: Moduli predefiniti abilitati per i nuovi progetti
- setting_gravatar_default: Immagine Gravatar predefinita
- field_sharing: Condivisione
- label_version_sharing_hierarchy: Con gerarchia progetto
- label_version_sharing_system: Con tutti i progetti
- label_version_sharing_descendants: Con sottoprogetti
- label_version_sharing_tree: Con progetto padre
- label_version_sharing_none: Nessuna condivisione
- error_can_not_archive_project: Questo progetto non può essere archiviato
- button_duplicate: Duplica
- button_copy_and_follow: Copia e segui
- label_copy_source: Sorgente
- setting_issue_done_ratio: Calcola la percentuale di segnalazioni completate con
- setting_issue_done_ratio_issue_status: Usa lo stato segnalazioni
- error_issue_done_ratios_not_updated: La percentuale delle segnalazioni completate non è aggiornata.
- error_workflow_copy_target: Per favore seleziona trackers finali e ruolo(i)
- setting_issue_done_ratio_issue_field: Usa il campo segnalazioni
- label_copy_same_as_target: Uguale a destinazione
- label_copy_target: Destinazione
- notice_issue_done_ratios_updated: La percentuale delle segnalazioni completate è aggiornata.
- error_workflow_copy_source: Per favore seleziona un tracker sorgente o ruolo
- label_update_issue_done_ratios: Aggiorna la percentuale delle segnalazioni completate
- setting_start_of_week: Avvia calendari il
- permission_view_issues: Mostra segnalazioni
- label_display_used_statuses_only: Mostra solo stati che vengono usati per questo tracker
- label_revision_id: Revisione %{value}
- label_api_access_key: Chiave di accesso API
- label_api_access_key_created_on: Chiave di accesso API creata %{value} fa
- label_feeds_access_key: Chiave di accesso RSS
- notice_api_access_key_reseted: La chiave di accesso API è stata reimpostata.
- setting_rest_api_enabled: Abilita il servizio web REST
- label_missing_api_access_key: Chiave di accesso API mancante
- label_missing_feeds_access_key: Chiave di accesso RSS mancante
- button_show: Mostra
- text_line_separated: Valori multipli permessi (un valore per ogni riga).
- setting_mail_handler_body_delimiters: Tronca email dopo una di queste righe
- permission_add_subprojects: Crea sottoprogetti
- label_subproject_new: Nuovo sottoprogetto
- text_own_membership_delete_confirmation: |-
- Stai per eliminare alcuni o tutti i permessi e non sarai più in grado di modificare questo progetto dopo tale azione.
- Sei sicuro di voler continuare?
- label_close_versions: Versioni completate chiuse
- label_board_sticky: Annunci
- label_board_locked: Bloccato
- permission_export_wiki_pages: Esporta pagine wiki
- setting_cache_formatted_text: Cache testo formattato
- permission_manage_project_activities: Gestisci attività progetti
- error_unable_delete_issue_status: Impossibile eliminare lo stato segnalazioni
- label_profile: Profilo
- permission_manage_subtasks: Gestisci sottoattivitÃ
- field_parent_issue: Attività principale
- label_subtask_plural: SottoattivitÃ
- label_project_copy_notifications: Invia notifiche email durante la copia del progetto
- error_can_not_delete_custom_field: Impossibile eliminare il campo personalizzato
- error_unable_to_connect: Impossibile connettersi (%{value})
- error_can_not_remove_role: Questo ruolo è in uso e non può essere eliminato.
- error_can_not_delete_tracker: Questo tracker contiene segnalazioni e non può essere eliminato.
- field_principal: Principale
- label_my_page_block: La mia pagina di blocco
- notice_failed_to_save_members: "Impossibile salvare il membro(i): %{errors}."
- text_zoom_out: Riduci ingrandimento
- text_zoom_in: Aumenta ingrandimento
- notice_unable_delete_time_entry: Impossibile eliminare il valore time log.
- label_overall_spent_time: Totale tempo impiegato
- field_time_entries: Tempo di collegamento
- project_module_gantt: Gantt
- project_module_calendar: Calendario
- button_edit_associated_wikipage: "Modifica la pagina wiki associata: %{page_title}"
- text_are_you_sure_with_children: Eliminare la segnalazione e tutte le discendenti?
- field_text: Campo di testo
- label_user_mail_option_only_owner: Solo se io sono il proprietario
- setting_default_notification_option: Opzione di notifica predefinita
- label_user_mail_option_only_my_events: Solo se sono un osservatore o sono coinvolto
- label_user_mail_option_only_assigned: Solo quando mi assegnano attivitÃ
- label_user_mail_option_none: Nessun evento
- field_member_of_group: Gruppo dell'assegnatario
- field_assigned_to_role: Ruolo dell'assegnatario
- notice_not_authorized_archived_project: Il progetto a cui stai accedendo è stato archiviato.
- label_principal_search: "Cerca utente o gruppo:"
- label_user_search: "Cerca utente:"
- field_visible: Visibile
- setting_emails_header: Intestazione email
- setting_commit_logtime_activity_id: Attività per il tempo di collegamento
- text_time_logged_by_changeset: Usato nel changeset %{value}.
- setting_commit_logtime_enabled: Abilita registrazione del tempo di collegamento
- notice_gantt_chart_truncated: Il grafico è stato troncato perchè eccede il numero di oggetti (%{max}) da visualizzare
- setting_gantt_items_limit: Massimo numero di oggetti da visualizzare sul diagramma di gantt
- field_warn_on_leaving_unsaved: Avvisami quando lascio una pagina con testo non salvato
- text_warn_on_leaving_unsaved: La pagina corrente contiene del testo non salvato che verrà perso se lasci questa pagina.
- label_my_queries: Le mie queries personalizzate
- text_journal_changed_no_detail: "%{label} aggiornato"
- label_news_comment_added: Commento aggiunto a una notizia
- button_expand_all: Espandi tutto
- button_collapse_all: Comprimi tutto
- label_additional_workflow_transitions_for_assignee: Transizioni supplementari consentite quando l'utente è l'assegnatario
- label_additional_workflow_transitions_for_author: Transizioni supplementari consentite quando l'utente è l'autore
- label_bulk_edit_selected_time_entries: Modifica massiva delle ore segnalate selezionate
- text_time_entries_destroy_confirmation: Sei sicuro di voler eliminare l'ora\e selezionata\e?
- label_role_anonymous: Anonimo
- label_role_non_member: Non membro
- label_issue_note_added: Nota aggiunta
- label_issue_status_updated: Stato aggiornato
- label_issue_priority_updated: Priorità aggiornata
- label_issues_visibility_own: Segnalazioni create o assegnate all'utente
- field_issues_visibility: Visibilità segnalazioni
- label_issues_visibility_all: Tutte le segnalazioni
- permission_set_own_issues_private: Imposta le proprie segnalazioni pubbliche o private
- field_is_private: Privato
- permission_set_issues_private: Imposta le segnalazioni pubbliche o private
- label_issues_visibility_public: Tutte le segnalazioni non private
- text_issues_destroy_descendants_confirmation: Questo eliminerà anche %{count} sottoattività .
- field_commit_logs_encoding: Codifica dei messaggi di commit
- field_scm_path_encoding: Codifica del percorso
- text_scm_path_encoding_note: "Predefinito: UTF-8"
- field_path_to_repository: Percorso del repository
- field_root_directory: Directory radice
- field_cvs_module: Modulo
- field_cvsroot: CVSROOT
- text_mercurial_repository_note: Repository locale (es. /hgrepo, c:\hgrepo)
- text_scm_command: Comando
- text_scm_command_version: Versione
- label_git_report_last_commit: Riporta l'ultimo commit per files e directories
- text_scm_config: Puoi configurare i comandi scm nel file config/configuration.yml. E' necessario riavviare l'applicazione dopo averlo modificato.
- text_scm_command_not_available: Il comando scm non è disponibile. Controllare le impostazioni nel pannello di amministrazione.
- notice_issue_successful_create: Segnalazione %{id} creata.
- label_between: tra
- setting_issue_group_assignment: Permetti di assegnare una segnalazione a gruppi
- label_diff: diff
- text_git_repository_note: Il repository è bare e locale (e.g. /gitrepo, c:\gitrepo)
- description_query_sort_criteria_direction: Ordinamento
- description_project_scope: Search scope
- description_filter: Filtro
- description_user_mail_notification: Impostazioni notifica via mail
- description_date_from: Inserisci la data d'inizio
- description_message_content: Contenuto del messaggio
- description_available_columns: Colonne disponibili
- description_date_range_interval: Scegli l'intervallo selezionando la data di inizio e di fine
- description_issue_category_reassign: Scegli la categoria della segnalazione
- description_search: Campo di ricerca
- description_notes: Note
- description_date_range_list: Scegli l'intervallo dalla lista
- description_choose_project: Progetti
- description_date_to: Inserisci la data di fine
- description_query_sort_criteria_attribute: Attributo di ordinamento
- description_wiki_subpages_reassign: Scegli la nuova pagina padre
- description_selected_columns: Colonne selezionate
- label_parent_revision: Padre
- label_child_revision: Figlio
- error_scm_annotate_big_text_file: La nota non può essere salvata, supera la dimensiona massima del campo di testo.
- setting_default_issue_start_date_to_creation_date: Usa la data corrente come data d'inizio per le nuove segnalazioni
- button_edit_section: Modifica questa sezione
- setting_repositories_encodings: Codifica degli allegati e dei repository
- description_all_columns: Tutte le colonne
- button_export: Esporta
- label_export_options: "%{export_format} opzioni per l'export"
- error_attachment_too_big: Questo file non può essere caricato in quanto la sua dimensione supera la massima consentita (%{max_size})
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/7a/7a99d287fc3d9f980fb731f44a9408d8010b9694.svn-base
--- a/.svn/pristine/7a/7a99d287fc3d9f980fb731f44a9408d8010b9694.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,199 +0,0 @@
-require File.expand_path('../../test_helper', __FILE__)
-
-class ProjectEnumerationsControllerTest < ActionController::TestCase
- fixtures :projects, :trackers, :issue_statuses, :issues,
- :enumerations, :users, :issue_categories,
- :projects_trackers,
- :roles,
- :member_roles,
- :members,
- :enabled_modules,
- :workflows,
- :custom_fields, :custom_fields_projects,
- :custom_fields_trackers, :custom_values,
- :time_entries
-
- def setup
- @request.session[:user_id] = nil
- Setting.default_language = 'en'
- end
-
- def test_update_to_override_system_activities
- @request.session[:user_id] = 2 # manager
- billable_field = TimeEntryActivityCustomField.find_by_name("Billable")
-
- put :update, :project_id => 1, :enumerations => {
- "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # Design, De-activate
- "10"=> {"parent_id"=>"10", "custom_field_values"=>{"7"=>"0"}, "active"=>"1"}, # Development, Change custom value
- "14"=>{"parent_id"=>"14", "custom_field_values"=>{"7"=>"1"}, "active"=>"1"}, # Inactive Activity, Activate with custom value
- "11"=>{"parent_id"=>"11", "custom_field_values"=>{"7"=>"1"}, "active"=>"1"} # QA, no changes
- }
-
- assert_response :redirect
- assert_redirected_to '/projects/ecookbook/settings/activities'
-
- # Created project specific activities...
- project = Project.find('ecookbook')
-
- # ... Design
- design = project.time_entry_activities.find_by_name("Design")
- assert design, "Project activity not found"
-
- assert_equal 9, design.parent_id # Relate to the system activity
- assert_not_equal design.parent.id, design.id # Different records
- assert_equal design.parent.name, design.name # Same name
- assert !design.active?
-
- # ... Development
- development = project.time_entry_activities.find_by_name("Development")
- assert development, "Project activity not found"
-
- assert_equal 10, development.parent_id # Relate to the system activity
- assert_not_equal development.parent.id, development.id # Different records
- assert_equal development.parent.name, development.name # Same name
- assert development.active?
- assert_equal "0", development.custom_value_for(billable_field).value
-
- # ... Inactive Activity
- previously_inactive = project.time_entry_activities.find_by_name("Inactive Activity")
- assert previously_inactive, "Project activity not found"
-
- assert_equal 14, previously_inactive.parent_id # Relate to the system activity
- assert_not_equal previously_inactive.parent.id, previously_inactive.id # Different records
- assert_equal previously_inactive.parent.name, previously_inactive.name # Same name
- assert previously_inactive.active?
- assert_equal "1", previously_inactive.custom_value_for(billable_field).value
-
- # ... QA
- assert_equal nil, project.time_entry_activities.find_by_name("QA"), "Custom QA activity created when it wasn't modified"
- end
-
- def test_update_will_update_project_specific_activities
- @request.session[:user_id] = 2 # manager
-
- project_activity = TimeEntryActivity.new({
- :name => 'Project Specific',
- :parent => TimeEntryActivity.find(:first),
- :project => Project.find(1),
- :active => true
- })
- assert project_activity.save
- project_activity_two = TimeEntryActivity.new({
- :name => 'Project Specific Two',
- :parent => TimeEntryActivity.find(:last),
- :project => Project.find(1),
- :active => true
- })
- assert project_activity_two.save
-
-
- put :update, :project_id => 1, :enumerations => {
- project_activity.id => {"custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # De-activate
- project_activity_two.id => {"custom_field_values"=>{"7" => "1"}, "active"=>"0"} # De-activate
- }
-
- assert_response :redirect
- assert_redirected_to '/projects/ecookbook/settings/activities'
-
- # Created project specific activities...
- project = Project.find('ecookbook')
- assert_equal 2, project.time_entry_activities.count
-
- activity_one = project.time_entry_activities.find_by_name(project_activity.name)
- assert activity_one, "Project activity not found"
- assert_equal project_activity.id, activity_one.id
- assert !activity_one.active?
-
- activity_two = project.time_entry_activities.find_by_name(project_activity_two.name)
- assert activity_two, "Project activity not found"
- assert_equal project_activity_two.id, activity_two.id
- assert !activity_two.active?
- end
-
- def test_update_when_creating_new_activities_will_convert_existing_data
- assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size
-
- @request.session[:user_id] = 2 # manager
- put :update, :project_id => 1, :enumerations => {
- "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"} # Design, De-activate
- }
- assert_response :redirect
-
- # No more TimeEntries using the system activity
- assert_equal 0, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size, "Time Entries still assigned to system activities"
- # All TimeEntries using project activity
- project_specific_activity = TimeEntryActivity.find_by_parent_id_and_project_id(9, 1)
- assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(project_specific_activity.id, 1).size, "No Time Entries assigned to the project activity"
- end
-
- def test_update_when_creating_new_activities_will_not_convert_existing_data_if_an_exception_is_raised
- # TODO: Need to cause an exception on create but these tests
- # aren't setup for mocking. Just create a record now so the
- # second one is a dupicate
- parent = TimeEntryActivity.find(9)
- TimeEntryActivity.create!({:name => parent.name, :project_id => 1, :position => parent.position, :active => true})
- TimeEntry.create!({:project_id => 1, :hours => 1.0, :user => User.find(1), :issue_id => 3, :activity_id => 10, :spent_on => '2009-01-01'})
-
- assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size
- assert_equal 1, TimeEntry.find_all_by_activity_id_and_project_id(10, 1).size
-
- @request.session[:user_id] = 2 # manager
- put :update, :project_id => 1, :enumerations => {
- "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # Design
- "10"=> {"parent_id"=>"10", "custom_field_values"=>{"7"=>"0"}, "active"=>"1"} # Development, Change custom value
- }
- assert_response :redirect
-
- # TimeEntries shouldn't have been reassigned on the failed record
- assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size, "Time Entries are not assigned to system activities"
- # TimeEntries shouldn't have been reassigned on the saved record either
- assert_equal 1, TimeEntry.find_all_by_activity_id_and_project_id(10, 1).size, "Time Entries are not assigned to system activities"
- end
-
- def test_destroy
- @request.session[:user_id] = 2 # manager
- project_activity = TimeEntryActivity.new({
- :name => 'Project Specific',
- :parent => TimeEntryActivity.find(:first),
- :project => Project.find(1),
- :active => true
- })
- assert project_activity.save
- project_activity_two = TimeEntryActivity.new({
- :name => 'Project Specific Two',
- :parent => TimeEntryActivity.find(:last),
- :project => Project.find(1),
- :active => true
- })
- assert project_activity_two.save
-
- delete :destroy, :project_id => 1
- assert_response :redirect
- assert_redirected_to '/projects/ecookbook/settings/activities'
-
- assert_nil TimeEntryActivity.find_by_id(project_activity.id)
- assert_nil TimeEntryActivity.find_by_id(project_activity_two.id)
- end
-
- def test_destroy_should_reassign_time_entries_back_to_the_system_activity
- @request.session[:user_id] = 2 # manager
- project_activity = TimeEntryActivity.new({
- :name => 'Project Specific Design',
- :parent => TimeEntryActivity.find(9),
- :project => Project.find(1),
- :active => true
- })
- assert project_activity.save
- assert TimeEntry.update_all("activity_id = '#{project_activity.id}'", ["project_id = ? AND activity_id = ?", 1, 9])
- assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(project_activity.id, 1).size
-
- delete :destroy, :project_id => 1
- assert_response :redirect
- assert_redirected_to '/projects/ecookbook/settings/activities'
-
- assert_nil TimeEntryActivity.find_by_id(project_activity.id)
- assert_equal 0, TimeEntry.find_all_by_activity_id_and_project_id(project_activity.id, 1).size, "TimeEntries still assigned to project specific activity"
- assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size, "TimeEntries still assigned to project specific activity"
- end
-
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/7a/7ae9d7b6d455faa0f47585102ed9dcb8d8884e01.svn-base
--- a/.svn/pristine/7a/7ae9d7b6d455faa0f47585102ed9dcb8d8884e01.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class BoardsController < ApplicationController
- default_search_scope :messages
- before_filter :find_project, :find_board_if_available, :authorize
- accept_rss_auth :index, :show
-
- helper :messages
- include MessagesHelper
- helper :sort
- include SortHelper
- helper :watchers
- include WatchersHelper
-
- def index
- @boards = @project.boards
- # show the board if there is only one
- if @boards.size == 1
- @board = @boards.first
- show
- end
- end
-
- def show
- respond_to do |format|
- format.html {
- sort_init 'updated_on', 'desc'
- sort_update 'created_on' => "#{Message.table_name}.created_on",
- 'replies' => "#{Message.table_name}.replies_count",
- 'updated_on' => "#{Message.table_name}.updated_on"
-
- @topic_count = @board.topics.count
- @topic_pages = Paginator.new self, @topic_count, per_page_option, params['page']
- @topics = @board.topics.find :all, :order => ["#{Message.table_name}.sticky DESC", sort_clause].compact.join(', '),
- :include => [:author, {:last_reply => :author}],
- :limit => @topic_pages.items_per_page,
- :offset => @topic_pages.current.offset
- @message = Message.new
- render :action => 'show', :layout => !request.xhr?
- }
- format.atom {
- @messages = @board.messages.find :all, :order => 'created_on DESC',
- :include => [:author, :board],
- :limit => Setting.feeds_limit.to_i
- render_feed(@messages, :title => "#{@project}: #{@board}")
- }
- end
- end
-
- verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index }
-
- def new
- @board = Board.new(params[:board])
- @board.project = @project
- if request.post? && @board.save
- flash[:notice] = l(:notice_successful_create)
- redirect_to_settings_in_projects
- end
- end
-
- def edit
- if request.post? && @board.update_attributes(params[:board])
- redirect_to_settings_in_projects
- end
- end
-
- def destroy
- @board.destroy
- redirect_to_settings_in_projects
- end
-
-private
- def redirect_to_settings_in_projects
- redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'boards'
- end
-
- def find_project
- @project = Project.find(params[:project_id])
- rescue ActiveRecord::RecordNotFound
- render_404
- end
-
- def find_board_if_available
- @board = @project.boards.find(params[:id]) if params[:id]
- rescue ActiveRecord::RecordNotFound
- render_404
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/7c/7c5921f65fb9645b9f52a7d0124578fab27871e2.svn-base
--- a/.svn/pristine/7c/7c5921f65fb9645b9f52a7d0124578fab27871e2.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-<% remote_form_for :repository, @repository,
- :url => { :controller => 'repositories', :action => 'edit', :id => @project },
- :builder => TabularFormBuilder,
- :lang => current_language do |f| %>
-
-<%= error_messages_for 'repository' %>
-
-
-
-<%= label_tag('repository_scm', l(:label_scm)) %><%= scm_select_tag(@repository) %>
-<% if @repository && ! @repository.class.scm_available %>
-
- <%= content_tag 'span', l(:text_scm_command_not_available), :class => 'error' %>
-<% end %>
-
-<% button_disabled = true %>
-<% if @repository %>
-<% button_disabled = ! @repository.class.scm_available %>
-<%= repository_field_tags(f, @repository)%>
-<% end %>
-
-
-
-<% if @repository && !@repository.new_record? %>
-<%= link_to(l(:label_user_plural),
- {
- :controller => 'repositories',
- :action => 'committers',
- :id => @project
- },
- :class => 'icon icon-user') %>
-<%= link_to(l(:button_delete), {:controller => 'repositories', :action => 'destroy', :id => @project},
- :confirm => l(:text_are_you_sure),
- :method => :post,
- :class => 'icon icon-del') %>
-<% end %>
-
-
-<%= submit_tag((@repository.nil? || @repository.new_record?) ? l(:button_create) : l(:button_save),
- :disabled => button_disabled) %>
-<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/7f/7f2b03891b8623abed7eda3f27f2af99b02de39f.svn-base
--- a/.svn/pristine/7f/7f2b03891b8623abed7eda3f27f2af99b02de39f.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,413 +0,0 @@
-package Apache::Authn::Redmine;
-
-=head1 Apache::Authn::Redmine
-
-Redmine - a mod_perl module to authenticate webdav subversion users
-against redmine database
-
-=head1 SYNOPSIS
-
-This module allow anonymous users to browse public project and
-registred users to browse and commit their project. Authentication is
-done against the redmine database or the LDAP configured in redmine.
-
-This method is far simpler than the one with pam_* and works with all
-database without an hassle but you need to have apache/mod_perl on the
-svn server.
-
-=head1 INSTALLATION
-
-For this to automagically work, you need to have a recent reposman.rb
-(after r860) and if you already use reposman, read the last section to
-migrate.
-
-Sorry ruby users but you need some perl modules, at least mod_perl2,
-DBI and DBD::mysql (or the DBD driver for you database as it should
-work on allmost all databases).
-
-On debian/ubuntu you must do :
-
- aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
-
-If your Redmine users use LDAP authentication, you will also need
-Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
-
- aptitude install libauthen-simple-ldap-perl libio-socket-ssl-perl
-
-=head1 CONFIGURATION
-
- ## This module has to be in your perl path
- ## eg: /usr/lib/perl5/Apache/Authn/Redmine.pm
- PerlLoadModule Apache::Authn::Redmine
-
- DAV svn
- SVNParentPath "/var/svn"
-
- AuthType Basic
- AuthName redmine
- Require valid-user
-
- PerlAccessHandler Apache::Authn::Redmine::access_handler
- PerlAuthenHandler Apache::Authn::Redmine::authen_handler
-
- ## for mysql
- RedmineDSN "DBI:mysql:database=databasename;host=my.db.server"
- ## for postgres
- # RedmineDSN "DBI:Pg:dbname=databasename;host=my.db.server"
-
- RedmineDbUser "redmine"
- RedmineDbPass "password"
- ## Optional where clause (fulltext search would be slow and
- ## database dependant).
- # RedmineDbWhereClause "and members.role_id IN (1,2)"
- ## Optional credentials cache size
- # RedmineCacheCredsMax 50
-
-
-To be able to browse repository inside redmine, you must add something
-like that :
-
-
- DAV svn
- SVNParentPath "/var/svn"
- Order deny,allow
- Deny from all
- # only allow reading orders
-
- Allow from redmine.server.ip
-
-
-
-and you will have to use this reposman.rb command line to create repository :
-
- reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
-
-=head1 MIGRATION FROM OLDER RELEASES
-
-If you use an older reposman.rb (r860 or before), you need to change
-rights on repositories to allow the apache user to read and write
-S
-
- sudo chown -R www-data /var/svn/*
- sudo chmod -R u+w /var/svn/*
-
-And you need to upgrade at least reposman.rb (after r860).
-
-=cut
-
-use strict;
-use warnings FATAL => 'all', NONFATAL => 'redefine';
-
-use DBI;
-use Digest::SHA1;
-# optional module for LDAP authentication
-my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
-
-use Apache2::Module;
-use Apache2::Access;
-use Apache2::ServerRec qw();
-use Apache2::RequestRec qw();
-use Apache2::RequestUtil qw();
-use Apache2::Const qw(:common :override :cmd_how);
-use APR::Pool ();
-use APR::Table ();
-
-# use Apache2::Directive qw();
-
-my @directives = (
- {
- name => 'RedmineDSN',
- req_override => OR_AUTHCFG,
- args_how => TAKE1,
- errmsg => 'Dsn in format used by Perl DBI. eg: "DBI:Pg:dbname=databasename;host=my.db.server"',
- },
- {
- name => 'RedmineDbUser',
- req_override => OR_AUTHCFG,
- args_how => TAKE1,
- },
- {
- name => 'RedmineDbPass',
- req_override => OR_AUTHCFG,
- args_how => TAKE1,
- },
- {
- name => 'RedmineDbWhereClause',
- req_override => OR_AUTHCFG,
- args_how => TAKE1,
- },
- {
- name => 'RedmineCacheCredsMax',
- req_override => OR_AUTHCFG,
- args_how => TAKE1,
- errmsg => 'RedmineCacheCredsMax must be decimal number',
- },
-);
-
-sub RedmineDSN {
- my ($self, $parms, $arg) = @_;
- $self->{RedmineDSN} = $arg;
- my $query = "SELECT
- hashed_password, salt, auth_source_id, permissions
- FROM projects, users, roles
- WHERE
- users.login=?
- AND projects.identifier=?
- AND users.status=1
- AND (
- roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id)
- OR
- (roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1'))
- ) ";
- $self->{RedmineQuery} = trim($query);
-}
-
-sub RedmineDbUser { set_val('RedmineDbUser', @_); }
-sub RedmineDbPass { set_val('RedmineDbPass', @_); }
-sub RedmineDbWhereClause {
- my ($self, $parms, $arg) = @_;
- $self->{RedmineQuery} = trim($self->{RedmineQuery}.($arg ? $arg : "")." ");
-}
-
-sub RedmineCacheCredsMax {
- my ($self, $parms, $arg) = @_;
- if ($arg) {
- $self->{RedmineCachePool} = APR::Pool->new;
- $self->{RedmineCacheCreds} = APR::Table::make($self->{RedmineCachePool}, $arg);
- $self->{RedmineCacheCredsCount} = 0;
- $self->{RedmineCacheCredsMax} = $arg;
- }
-}
-
-sub trim {
- my $string = shift;
- $string =~ s/\s{2,}/ /g;
- return $string;
-}
-
-sub set_val {
- my ($key, $self, $parms, $arg) = @_;
- $self->{$key} = $arg;
-}
-
-Apache2::Module::add(__PACKAGE__, \@directives);
-
-
-my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
-
-sub access_handler {
- my $r = shift;
-
- unless ($r->some_auth_required) {
- $r->log_reason("No authentication has been configured");
- return FORBIDDEN;
- }
-
- my $method = $r->method;
- return OK unless defined $read_only_methods{$method};
-
- my $project_id = get_project_identifier($r);
-
- $r->set_handlers(PerlAuthenHandler => [\&OK])
- if is_public_project($project_id, $r) && anonymous_role_allows_browse_repository($r);
-
- return OK
-}
-
-sub authen_handler {
- my $r = shift;
-
- my ($res, $redmine_pass) = $r->get_basic_auth_pw();
- return $res unless $res == OK;
-
- if (is_member($r->user, $redmine_pass, $r)) {
- return OK;
- } else {
- $r->note_auth_failure();
- return AUTH_REQUIRED;
- }
-}
-
-# check if authentication is forced
-sub is_authentication_forced {
- my $r = shift;
-
- my $dbh = connect_database($r);
- my $sth = $dbh->prepare(
- "SELECT value FROM settings where settings.name = 'login_required';"
- );
-
- $sth->execute();
- my $ret = 0;
- if (my @row = $sth->fetchrow_array) {
- if ($row[0] eq "1" || $row[0] eq "t") {
- $ret = 1;
- }
- }
- $sth->finish();
- undef $sth;
-
- $dbh->disconnect();
- undef $dbh;
-
- $ret;
-}
-
-sub is_public_project {
- my $project_id = shift;
- my $r = shift;
-
- if (is_authentication_forced($r)) {
- return 0;
- }
-
- my $dbh = connect_database($r);
- my $sth = $dbh->prepare(
- "SELECT is_public FROM projects WHERE projects.identifier = ?;"
- );
-
- $sth->execute($project_id);
- my $ret = 0;
- if (my @row = $sth->fetchrow_array) {
- if ($row[0] eq "1" || $row[0] eq "t") {
- $ret = 1;
- }
- }
- $sth->finish();
- undef $sth;
- $dbh->disconnect();
- undef $dbh;
-
- $ret;
-}
-
-sub anonymous_role_allows_browse_repository {
- my $r = shift;
-
- my $dbh = connect_database($r);
- my $sth = $dbh->prepare(
- "SELECT permissions FROM roles WHERE builtin = 2;"
- );
-
- $sth->execute();
- my $ret = 0;
- if (my @row = $sth->fetchrow_array) {
- if ($row[0] =~ /:browse_repository/) {
- $ret = 1;
- }
- }
- $sth->finish();
- undef $sth;
- $dbh->disconnect();
- undef $dbh;
-
- $ret;
-}
-
-# perhaps we should use repository right (other read right) to check public access.
-# it could be faster BUT it doesn't work for the moment.
-# sub is_public_project_by_file {
-# my $project_id = shift;
-# my $r = shift;
-
-# my $tree = Apache2::Directive::conftree();
-# my $node = $tree->lookup('Location', $r->location);
-# my $hash = $node->as_hash;
-
-# my $svnparentpath = $hash->{SVNParentPath};
-# my $repos_path = $svnparentpath . "/" . $project_id;
-# return 1 if (stat($repos_path))[2] & 00007;
-# }
-
-sub is_member {
- my $redmine_user = shift;
- my $redmine_pass = shift;
- my $r = shift;
-
- my $dbh = connect_database($r);
- my $project_id = get_project_identifier($r);
-
- my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
-
- my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W";
-
- my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
- my $usrprojpass;
- if ($cfg->{RedmineCacheCredsMax}) {
- $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode);
- return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
- }
- my $query = $cfg->{RedmineQuery};
- my $sth = $dbh->prepare($query);
- $sth->execute($redmine_user, $project_id);
-
- my $ret;
- while (my ($hashed_password, $salt, $auth_source_id, $permissions) = $sth->fetchrow_array) {
-
- unless ($auth_source_id) {
- my $method = $r->method;
- my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest);
- if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
- $ret = 1;
- last;
- }
- } elsif ($CanUseLDAPAuth) {
- my $sthldap = $dbh->prepare(
- "SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
- );
- $sthldap->execute($auth_source_id);
- while (my @rowldap = $sthldap->fetchrow_array) {
- my $ldap = Authen::Simple::LDAP->new(
- host => ($rowldap[2] eq "1" || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]:$rowldap[1]" : $rowldap[0],
- port => $rowldap[1],
- basedn => $rowldap[5],
- binddn => $rowldap[3] ? $rowldap[3] : "",
- bindpw => $rowldap[4] ? $rowldap[4] : "",
- filter => "(".$rowldap[6]."=%s)"
- );
- my $method = $r->method;
- $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
-
- }
- $sthldap->finish();
- undef $sthldap;
- }
- }
- $sth->finish();
- undef $sth;
- $dbh->disconnect();
- undef $dbh;
-
- if ($cfg->{RedmineCacheCredsMax} and $ret) {
- if (defined $usrprojpass) {
- $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
- } else {
- if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
- $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
- $cfg->{RedmineCacheCredsCount}++;
- } else {
- $cfg->{RedmineCacheCreds}->clear();
- $cfg->{RedmineCacheCredsCount} = 0;
- }
- }
- }
-
- $ret;
-}
-
-sub get_project_identifier {
- my $r = shift;
-
- my $location = $r->location;
- my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
- $identifier;
-}
-
-sub connect_database {
- my $r = shift;
-
- my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
- return DBI->connect($cfg->{RedmineDSN}, $cfg->{RedmineDbUser}, $cfg->{RedmineDbPass});
-}
-
-1;
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/81/8150bf5b8c067659e615bbcb4f9a5a40975b2bf9.svn-base
--- a/.svn/pristine/81/8150bf5b8c067659e615bbcb4f9a5a40975b2bf9.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-class Comment < ActiveRecord::Base
- generator_for :commented, :method => :generate_news
- generator_for :author, :method => :generate_author
- generator_for :comments => 'What great news this is.'
-
- def self.generate_news
- News.generate!
- end
-
- def self.generate_author
- User.generate_with_protected!
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/82/82b5527b2dac372076831682e718c16438363e58.svn-base
--- a/.svn/pristine/82/82b5527b2dac372076831682e718c16438363e58.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-class Attachment < ActiveRecord::Base
- generator_for :container, :method => :generate_project
- generator_for :file, :method => :generate_file
- generator_for :author, :method => :generate_author
-
- def self.generate_project
- Project.generate!
- end
-
- def self.generate_author
- User.generate_with_protected!
- end
-
- def self.generate_file
- @file = ActiveSupport::TestCase.mock_file
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/85/85316aa62f266023688bb5d8d7b7c31ca5b820f1.svn-base
--- a/.svn/pristine/85/85316aa62f266023688bb5d8d7b7c31ca5b820f1.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class MessagesController < ApplicationController
- menu_item :boards
- default_search_scope :messages
- before_filter :find_board, :only => [:new, :preview]
- before_filter :find_message, :except => [:new, :preview]
- before_filter :authorize, :except => [:preview, :edit, :destroy]
-
- verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show }
- verify :xhr => true, :only => :quote
-
- helper :watchers
- helper :attachments
- include AttachmentsHelper
-
- REPLIES_PER_PAGE = 25 unless const_defined?(:REPLIES_PER_PAGE)
-
- # Show a topic and its replies
- def show
- page = params[:page]
- # Find the page of the requested reply
- if params[:r] && page.nil?
- offset = @topic.children.count(:conditions => ["#{Message.table_name}.id < ?", params[:r].to_i])
- page = 1 + offset / REPLIES_PER_PAGE
- end
-
- @reply_count = @topic.children.count
- @reply_pages = Paginator.new self, @reply_count, REPLIES_PER_PAGE, page
- @replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}],
- :order => "#{Message.table_name}.created_on ASC",
- :limit => @reply_pages.items_per_page,
- :offset => @reply_pages.current.offset)
-
- @reply = Message.new(:subject => "RE: #{@message.subject}")
- render :action => "show", :layout => false if request.xhr?
- end
-
- # Create a new topic
- def new
- @message = Message.new(params[:message])
- @message.author = User.current
- @message.board = @board
- if params[:message] && User.current.allowed_to?(:edit_messages, @project)
- @message.locked = params[:message]['locked']
- @message.sticky = params[:message]['sticky']
- end
- if request.post? && @message.save
- call_hook(:controller_messages_new_after_save, { :params => params, :message => @message})
- attachments = Attachment.attach_files(@message, params[:attachments])
- render_attachment_warning_if_needed(@message)
- redirect_to :action => 'show', :id => @message
- end
- end
-
- # Reply to a topic
- def reply
- @reply = Message.new(params[:reply])
- @reply.author = User.current
- @reply.board = @board
- @topic.children << @reply
- if !@reply.new_record?
- call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply})
- attachments = Attachment.attach_files(@reply, params[:attachments])
- render_attachment_warning_if_needed(@reply)
- end
- redirect_to :action => 'show', :id => @topic, :r => @reply
- end
-
- # Edit a message
- def edit
- (render_403; return false) unless @message.editable_by?(User.current)
- if params[:message]
- @message.locked = params[:message]['locked']
- @message.sticky = params[:message]['sticky']
- end
- if request.post? && @message.update_attributes(params[:message])
- attachments = Attachment.attach_files(@message, params[:attachments])
- render_attachment_warning_if_needed(@message)
- flash[:notice] = l(:notice_successful_update)
- @message.reload
- redirect_to :action => 'show', :board_id => @message.board, :id => @message.root, :r => (@message.parent_id && @message.id)
- end
- end
-
- # Delete a messages
- def destroy
- (render_403; return false) unless @message.destroyable_by?(User.current)
- @message.destroy
- redirect_to @message.parent.nil? ?
- { :controller => 'boards', :action => 'show', :project_id => @project, :id => @board } :
- { :action => 'show', :id => @message.parent, :r => @message }
- end
-
- def quote
- user = @message.author
- text = @message.content
- subject = @message.subject.gsub('"', '\"')
- subject = "RE: #{subject}" unless subject.starts_with?('RE:')
- content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> "
- content << text.to_s.strip.gsub(%r{((.|\s)*?) }m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n"
- render(:update) { |page|
- page << "$('message_subject').value = \"#{subject}\";"
- page.<< "$('message_content').value = \"#{content}\";"
- page.show 'reply'
- page << "Form.Element.focus('message_content');"
- page << "Element.scrollTo('reply');"
- page << "$('message_content').scrollTop = $('message_content').scrollHeight - $('message_content').clientHeight;"
- }
- end
-
- def preview
- message = @board.messages.find_by_id(params[:id])
- @attachements = message.attachments if message
- @text = (params[:message] || params[:reply])[:content]
- render :partial => 'common/preview'
- end
-
-private
- def find_message
- find_board
- @message = @board.messages.find(params[:id], :include => :parent)
- @topic = @message.root
- rescue ActiveRecord::RecordNotFound
- render_404
- end
-
- def find_board
- @board = Board.find(params[:board_id], :include => :project)
- @project = @board.project
- rescue ActiveRecord::RecordNotFound
- render_404
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/86/86fc0dc108949dafb75bfcb3403e9b3a41c1387b.svn-base
--- a/.svn/pristine/86/86fc0dc108949dafb75bfcb3403e9b3a41c1387b.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-# encoding: utf-8
-#
-module IssueMovesHelper
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/89/89de0a30fbe820a24f361c69ba0c73b295dd67c1.svn-base
--- a/.svn/pristine/89/89de0a30fbe820a24f361c69ba0c73b295dd67c1.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-class WikiRedirect < ActiveRecord::Base
- generator_for :title, :start => 'AWikiPage'
- generator_for :redirects_to, :start => '/a/path/000001'
- generator_for :wiki, :method => :generate_wiki
-
- def self.generate_wiki
- Wiki.generate!
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/8d/8dc228786073bdd226ed8ffeeb72abeba31ad9e2.svn-base
--- a/.svn/pristine/8d/8dc228786073bdd226ed8ffeeb72abeba31ad9e2.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class UserPreference < ActiveRecord::Base
- belongs_to :user
- serialize :others
-
- attr_protected :others
-
- def initialize(attributes = nil)
- super
- self.others ||= {}
- end
-
- def before_save
- self.others ||= {}
- end
-
- def [](attr_name)
- if attribute_present? attr_name
- super
- else
- others ? others[attr_name] : nil
- end
- end
-
- def []=(attr_name, value)
- if attribute_present? attr_name
- super
- else
- h = read_attribute(:others).dup || {}
- h.update(attr_name => value)
- write_attribute(:others, h)
- value
- end
- end
-
- def comments_sorting; self[:comments_sorting] end
- def comments_sorting=(order); self[:comments_sorting]=order end
-
- def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end
- def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/94/9420193bff8376d2dce9c8e234846cba9d32146a.svn-base
--- a/.svn/pristine/94/9420193bff8376d2dce9c8e234846cba9d32146a.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-module IssueStatusesHelper
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/94/949c58e9921f8706f6e0819c20be1983b0201da0.svn-base
--- a/.svn/pristine/94/949c58e9921f8706f6e0819c20be1983b0201da0.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-class CustomValue < ActiveRecord::Base
- generator_for :custom_field, :method => :generate_custom_field
-
- def self.generate_custom_field
- CustomField.generate!
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/97/97e2dd2e74f4e5e23e73418a86b7b66188c24bd7.svn-base
--- a/.svn/pristine/97/97e2dd2e74f4e5e23e73418a86b7b66188c24bd7.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,990 +0,0 @@
-nl:
- direction: ltr
- date:
- formats:
- # Use the strftime parameters for formats.
- # When no format has been given, it uses default.
- # You can provide other formats here if you like!
- default: "%d-%m-%Y"
- short: "%e %b"
- long: "%d %B, %Y"
-
- day_names: [zondag, maandag, dinsdag, woensdag, donderdag, vrijdag, zaterdag]
- abbr_day_names: [zo, ma, di, wo, do, vr, za]
-
- # Don't forget the nil at the beginning; there's no such thing as a 0th month
- month_names: [~, januari, februari, maart, april, mei, juni, juli, augustus, september, oktober, november, december]
- abbr_month_names: [~, jan, feb, mar, apr, mei, jun, jul, aug, sep, okt, nov, dec]
- # Used in date_select and datime_select.
- order:
- - :day
- - :month
- - :year
-
- time:
- formats:
- default: "%a, %d %b %Y %H:%M:%S %z"
- time: "%H:%M"
- short: "%e %b %H:%M"
- long: "%d %B, %Y %H:%M"
- am: "am"
- pm: "pm"
-
- datetime:
- distance_in_words:
- half_a_minute: "halve minuut"
- less_than_x_seconds:
- one: "minder dan een seconde"
- other: "minder dan %{count} seconden"
- x_seconds:
- one: "1 seconde"
- other: "%{count} seconden"
- less_than_x_minutes:
- one: "minder dan een minuut"
- other: "minder dan %{count} minuten"
- x_minutes:
- one: "1 minuut"
- other: "%{count} minuten"
- about_x_hours:
- one: "ongeveer 1 uur"
- other: "ongeveer %{count} uren"
- x_days:
- one: "1 dag"
- other: "%{count} dagen"
- about_x_months:
- one: "ongeveer 1 maand"
- other: "ongeveer %{count} maanden"
- x_months:
- one: "1 maand"
- other: "%{count} maanden"
- about_x_years:
- one: "ongeveer 1 jaar"
- other: "ongeveer %{count} jaar"
- over_x_years:
- one: "meer dan 1 jaar"
- other: "meer dan %{count} jaar"
- almost_x_years:
- one: "bijna 1 jaar"
- other: "bijna %{count} jaar"
-
- number:
- format:
- separator: "."
- delimiter: ""
- precision: 3
- human:
- format:
- precision: 1
- delimiter: ""
- storage_units:
- format: "%n %u"
- units:
- kb: KB
- tb: TB
- gb: GB
- byte:
- one: Byte
- other: Bytes
- mb: MB
-
-# Used in array.to_sentence.
- support:
- array:
- sentence_connector: "en"
- skip_last_comma: false
-
- activerecord:
- errors:
- template:
- header:
- one: "Door een fout kon dit %{model} niet worden opgeslagen"
- other: "Door %{count} fouten kon dit %{model} niet worden opgeslagen"
- messages:
- inclusion: "staat niet in de lijst"
- exclusion: "is gereserveerd"
- invalid: "is ongeldig"
- confirmation: "komt niet overeen met bevestiging"
- accepted: "moet geaccepteerd worden"
- empty: "mag niet leeg zijn"
- blank: "mag niet blanco zijn"
- too_long: "is te lang"
- too_short: "is te kort"
- wrong_length: "heeft een onjuiste lengte"
- taken: "is al in gebruik"
- not_a_number: "is geen getal"
- not_a_date: "is geen valide datum"
- greater_than: "moet groter zijn dan %{count}"
- greater_than_or_equal_to: "moet groter zijn of gelijk zijn aan %{count}"
- equal_to: "moet gelijk zijn aan %{count}"
- less_than: "moet minder zijn dan %{count}"
- less_than_or_equal_to: "moet minder dan of gelijk zijn aan %{count}"
- odd: "moet oneven zijn"
- even: "moet even zijn"
- greater_than_start_date: "moet na de startdatum liggen"
- not_same_project: "hoort niet bij hetzelfde project"
- circular_dependency: "Deze relatie zou een circulaire afhankelijkheid tot gevolg hebben"
- cant_link_an_issue_with_a_descendant: "Een issue kan niet gelinked worden met een subtask"
-
- actionview_instancetag_blank_option: Selecteer
-
- button_activate: Activeer
- button_add: Voeg toe
- button_annotate: Annoteer
- button_apply: Pas toe
- button_archive: Archiveer
- button_back: Terug
- button_cancel: Annuleer
- button_change: Wijzig
- button_change_password: Wijzig wachtwoord
- button_check_all: Selecteer alle
- button_clear: Leeg maken
- button_configure: Configureer
- button_copy: Kopiëer
- button_create: Maak
- button_delete: Verwijder
- button_download: Download
- button_edit: Bewerk
- button_list: Lijst
- button_lock: Sluit
- button_log_time: Registreer tijd
- button_login: Inloggen
- button_move: Verplaatsen
- button_quote: Citaat
- button_rename: Hernoemen
- button_reply: Antwoord
- button_reset: Reset
- button_rollback: Rollback naar deze versie
- button_save: Bewaren
- button_sort: Sorteer
- button_submit: Toevoegen
- button_test: Test
- button_unarchive: Dearchiveer
- button_uncheck_all: Deselecteer alle
- button_unlock: Open
- button_unwatch: Niet meer monitoren
- button_update: Update
- button_view: Bekijken
- button_watch: Monitor
- default_activity_design: Ontwerp
- default_activity_development: Ontwikkeling
- default_doc_category_tech: Technische documentatie
- default_doc_category_user: Gebruikersdocumentatie
- default_issue_status_in_progress: In Progress
- default_issue_status_closed: Gesloten
- default_issue_status_feedback: Terugkoppeling
- default_issue_status_new: Nieuw
- default_issue_status_rejected: Afgewezen
- default_issue_status_resolved: Opgelost
- default_priority_high: Hoog
- default_priority_immediate: Onmiddellijk
- default_priority_low: Laag
- default_priority_normal: Normaal
- default_priority_urgent: Spoed
- default_role_developer: Ontwikkelaar
- default_role_manager: Manager
- default_role_reporter: Rapporteur
- default_tracker_bug: Bug
- default_tracker_feature: Feature
- default_tracker_support: Support
- enumeration_activities: Activiteiten (tijdtracking)
- enumeration_doc_categories: Documentcategorieën
- enumeration_issue_priorities: Issueprioriteiten
- error_can_t_load_default_data: "De standaard configuratie kon niet worden geladen: %{value}"
- error_issue_not_found_in_project: 'Deze issue is niet gevonden of behoort niet toe tot dit project.'
- error_scm_annotate: "Er kan geen commentaar toegevoegd worden."
- error_scm_command_failed: "Er trad een fout op tijdens de poging om verbinding te maken met de repository: %{value}"
- error_scm_not_found: "Deze ingang of revisie bestaat niet in de repository."
- field_account: Account
- field_activity: Activiteit
- field_admin: Beheerder
- field_assignable: Issues kunnen toegewezen worden aan deze rol
- field_assigned_to: Toegewezen aan
- field_attr_firstname: Voornaam attribuut
- field_attr_lastname: Achternaam attribuut
- field_attr_login: Login attribuut
- field_attr_mail: E-mail attribuut
- field_auth_source: Authenticatiemethode
- field_author: Auteur
- field_base_dn: Base DN
- field_category: Categorie
- field_column_names: Kolommen
- field_comments: Commentaar
- field_comments_sorting: Commentaar weergeven
- field_created_on: Aangemaakt
- field_default_value: Standaardwaarde
- field_delay: Vertraging
- field_description: Beschrijving
- field_done_ratio: "% Gereed"
- field_downloads: Downloads
- field_due_date: Verwachte datum gereed
- field_effective_date: Datum
- field_estimated_hours: Geschatte tijd
- field_field_format: Formaat
- field_filename: Bestand
- field_filesize: Grootte
- field_firstname: Voornaam
- field_fixed_version: Versie
- field_hide_mail: Verberg mijn e-mailadres
- field_homepage: Homepage
- field_host: Host
- field_hours: Uren
- field_identifier: Identificatiecode
- field_is_closed: Issue gesloten
- field_is_default: Standaard
- field_is_filter: Gebruikt als een filter
- field_is_for_all: Voor alle projecten
- field_is_in_roadmap: Issues weergegeven in roadmap
- field_is_public: Publiek
- field_is_required: Verplicht
- field_issue: Issue
- field_issue_to: Gerelateerd issue
- field_language: Taal
- field_last_login_on: Laatste bezoek
- field_lastname: Achternaam
- field_login: Inloggen
- field_mail: E-mail
- field_mail_notification: Mail mededelingen
- field_max_length: Maximale lengte
- field_min_length: Minimale lengte
- field_name: Naam
- field_new_password: Nieuw wachtwoord
- field_notes: Notities
- field_onthefly: On-the-fly aanmaken van een gebruiker
- field_parent: Subproject van
- field_parent_title: Bovenliggende pagina
- field_password: Wachtwoord
- field_password_confirmation: Bevestigen
- field_port: Port
- field_possible_values: Mogelijke waarden
- field_priority: Prioriteit
- field_project: Project
- field_redirect_existing_links: Verwijs bestaande links door
- field_regexp: Reguliere expressie
- field_role: Rol
- field_searchable: Doorzoekbaar
- field_spent_on: Datum
- field_start_date: Startdatum
- field_start_page: Startpagina
- field_status: Status
- field_subject: Onderwerp
- field_subproject: Subproject
- field_summary: Samenvatting
- field_time_zone: Tijdzone
- field_title: Titel
- field_tracker: Tracker
- field_type: Type
- field_updated_on: Gewijzigd
- field_url: URL
- field_user: Gebruiker
- field_value: Waarde
- field_version: Versie
- general_csv_decimal_separator: ','
- general_csv_encoding: ISO-8859-1
- general_csv_separator: ';'
- general_first_day_of_week: '7'
- general_lang_name: 'Nederlands'
- general_pdf_encoding: UTF-8
- general_text_No: 'Nee'
- general_text_Yes: 'Ja'
- general_text_no: 'nee'
- general_text_yes: 'ja'
- gui_validation_error: 1 fout
- gui_validation_error_plural: "%{count} fouten"
- label_activity: Activiteit
- label_add_another_file: Ander bestand toevoegen
- label_add_note: Voeg een notitie toe
- label_added: toegevoegd
- label_added_time_by: "Toegevoegd door %{author} %{age} geleden"
- label_administration: Administratie
- label_age: Leeftijd
- label_ago: dagen geleden
- label_all: alle
- label_all_time: alles
- label_all_words: Alle woorden
- label_and_its_subprojects: "%{value} en zijn subprojecten."
- label_applied_status: Toegekende status
- label_assigned_to_me_issues: Aan mij toegewezen issues
- label_associated_revisions: Geassociëerde revisies
- label_attachment: Bestand
- label_attachment_delete: Verwijder bestand
- label_attachment_new: Nieuw bestand
- label_attachment_plural: Bestanden
- label_attribute: Attribuut
- label_attribute_plural: Attributen
- label_auth_source: Authenticatiemodus
- label_auth_source_new: Nieuwe authenticatiemodus
- label_auth_source_plural: Authenticatiemodi
- label_authentication: Authenticatie
- label_blocked_by: geblokkeerd door
- label_blocks: blokkeert
- label_board: Forum
- label_board_new: Nieuw forum
- label_board_plural: Forums
- label_boolean: Boolean
- label_browse: Blader
- label_bulk_edit_selected_issues: Bewerk geselecteerde issues in bulk
- label_calendar: Kalender
- label_change_plural: Wijzigingen
- label_change_properties: Eigenschappen wijzigen
- label_change_status: Wijzig status
- label_change_view_all: Bekijk alle wijzigingen
- label_changes_details: Details van alle wijzigingen
- label_changeset_plural: Changesets
- label_chronological_order: In chronologische volgorde
- label_closed_issues: gesloten
- label_closed_issues_plural: gesloten
- label_x_open_issues_abbr_on_total:
- zero: 0 open / %{total}
- one: 1 open / %{total}
- other: "%{count} open / %{total}"
- label_x_open_issues_abbr:
- zero: 0 open
- one: 1 open
- other: "%{count} open"
- label_x_closed_issues_abbr:
- zero: 0 closed
- one: 1 closed
- other: "%{count} closed"
- label_comment: Commentaar
- label_comment_add: Voeg commentaar toe
- label_comment_added: Commentaar toegevoegd
- label_comment_delete: Verwijder commentaar
- label_comment_plural: Commentaar
- label_x_comments:
- zero: no comments
- one: 1 comment
- other: "%{count} comments"
- label_commits_per_author: Commits per auteur
- label_commits_per_month: Commits per maand
- label_confirmation: Bevestiging
- label_contains: bevat
- label_copied: gekopieerd
- label_copy_workflow_from: Kopieer workflow van
- label_current_status: Huidige status
- label_current_version: Huidige versie
- label_custom_field: Specifiek veld
- label_custom_field_new: Nieuw specifiek veld
- label_custom_field_plural: Specifieke velden
- label_date: Datum
- label_date_from: Van
- label_date_range: Datumbereik
- label_date_to: Tot
- label_day_plural: dagen
- label_default: Standaard
- label_default_columns: Standaard kolommen.
- label_deleted: verwijderd
- label_details: Details
- label_diff_inline: inline
- label_diff_side_by_side: naast elkaar
- label_disabled: uitgeschakeld
- label_display_per_page: "Per pagina: %{value}"
- label_document: Document
- label_document_added: Document toegevoegd
- label_document_new: Nieuw document
- label_document_plural: Documenten
- label_download: "%{count} Download"
- label_download_plural: "%{count} Downloads"
- label_downloads_abbr: D/L
- label_duplicated_by: gedupliceerd door
- label_duplicates: dupliceert
- label_end_to_end: eind tot eind
- label_end_to_start: eind tot start
- label_enumeration_new: Nieuwe waarde
- label_enumerations: Enumeraties
- label_environment: Omgeving
- label_equals: is gelijk
- label_example: Voorbeeld
- label_export_to: Exporteer naar
- label_f_hour: "%{value} uur"
- label_f_hour_plural: "%{value} uren"
- label_feed_plural: Feeds
- label_feeds_access_key_created_on: "RSS toegangssleutel %{value} geleden gemaakt."
- label_file_added: Bericht toegevoegd
- label_file_plural: Bestanden
- label_filter_add: Voeg filter toe
- label_filter_plural: Filters
- label_float: Float
- label_follows: volgt op
- label_gantt: Gantt
- label_general: Algemeen
- label_generate_key: Genereer een sleutel
- label_help: Help
- label_history: Geschiedenis
- label_home: Home
- label_in: in
- label_in_less_than: in minder dan
- label_in_more_than: in meer dan
- label_incoming_emails: Inkomende e-mail
- label_index_by_date: Indexeer op datum
- label_index_by_title: Indexeer op titel
- label_information: Informatie
- label_information_plural: Informatie
- label_integer: Integer
- label_internal: Intern
- label_issue: Issue
- label_issue_added: Issue toegevoegd
- label_issue_category: Issuecategorie
- label_issue_category_new: Nieuwe categorie
- label_issue_category_plural: Issuecategorieën
- label_issue_new: Nieuw issue
- label_issue_plural: Issues
- label_issue_status: Issuestatus
- label_issue_status_new: Nieuwe status
- label_issue_status_plural: Issue statussen
- label_issue_tracking: Issue-tracking
- label_issue_updated: Issue bijgewerkt
- label_issue_view_all: Bekijk alle issues
- label_issue_watchers: Monitoren
- label_issues_by: "Issues door %{value}"
- label_jump_to_a_project: Ga naar een project...
- label_language_based: Taal gebaseerd
- label_last_changes: "laatste %{count} wijzigingen"
- label_last_login: Laatste bezoek
- label_last_month: laatste maand
- label_last_n_days: "%{count} dagen geleden"
- label_last_week: vorige week
- label_latest_revision: Meest recente revisie
- label_latest_revision_plural: Meest recente revisies
- label_ldap_authentication: LDAP authenticatie
- label_less_than_ago: minder dan x dagen geleden
- label_list: Lijst
- label_loading: Laden...
- label_logged_as: Ingelogd als
- label_login: Inloggen
- label_logout: Uitloggen
- label_max_size: Maximumgrootte
- label_me: mij
- label_member: Lid
- label_member_new: Nieuw lid
- label_member_plural: Leden
- label_message_last: Laatste bericht
- label_message_new: Nieuw bericht
- label_message_plural: Berichten
- label_message_posted: Bericht toegevoegd
- label_min_max_length: Min-max lengte
- label_modification: "%{count} wijziging"
- label_modification_plural: "%{count} wijzigingen"
- label_modified: gewijzigd
- label_module_plural: Modules
- label_month: Maand
- label_months_from: maanden vanaf
- label_more: Meer
- label_more_than_ago: meer dan x dagen geleden
- label_my_account: Mijn account
- label_my_page: Mijn pagina
- label_my_projects: Mijn projecten
- label_new: Nieuw
- label_new_statuses_allowed: Nieuwe toegestane statussen
- label_news: Nieuws
- label_news_added: Nieuws toegevoegd
- label_news_latest: Laatste nieuws
- label_news_new: Voeg nieuws toe
- label_news_plural: Nieuws
- label_news_view_all: Bekijk al het nieuws
- label_next: Volgende
- label_no_change_option: (Geen wijziging)
- label_no_data: Geen gegevens om te tonen
- label_nobody: niemand
- label_none: geen
- label_not_contains: bevat niet
- label_not_equals: is niet gelijk
- label_open_issues: open
- label_open_issues_plural: open
- label_optional_description: Optionele beschrijving
- label_options: Opties
- label_overall_activity: Activiteit
- label_overview: Overzicht
- label_password_lost: Wachtwoord verloren
- label_per_page: Per pagina
- label_permissions: Permissies
- label_permissions_report: Permissierapport
- label_personalize_page: Personaliseer deze pagina
- label_planning: Planning
- label_please_login: Log a.u.b. in
- label_plugins: Plugins
- label_precedes: gaat vooraf aan
- label_preferences: Voorkeuren
- label_preview: Voorbeeldweergave
- label_previous: Vorige
- label_project: Project
- label_project_all: Alle projecten
- label_project_latest: Nieuwste projecten
- label_project_new: Nieuw project
- label_project_plural: Projecten
- label_x_projects:
- zero: no projects
- one: 1 project
- other: "%{count} projects"
- label_public_projects: Publieke projecten
- label_query: Eigen zoekopdracht
- label_query_new: Nieuwe zoekopdracht
- label_query_plural: Eigen zoekopdrachten
- label_read: Lees...
- label_register: Registreer
- label_registered_on: Geregistreerd op
- label_registration_activation_by_email: accountactivatie per e-mail
- label_registration_automatic_activation: automatische accountactivatie
- label_registration_manual_activation: handmatige accountactivatie
- label_related_issues: Gerelateerde issues
- label_relates_to: gerelateerd aan
- label_relation_delete: Verwijder relatie
- label_relation_new: Nieuwe relatie
- label_renamed: hernoemd
- label_reply_plural: Antwoorden
- label_report: Rapport
- label_report_plural: Rapporten
- label_reported_issues: Gemelde issues
- label_repository: Repository
- label_repository_plural: Repositories
- label_result_plural: Resultaten
- label_reverse_chronological_order: In omgekeerde chronologische volgorde
- label_revision: Revisie
- label_revision_plural: Revisies
- label_roadmap: Roadmap
- label_roadmap_due_in: "Voldaan in %{value}"
- label_roadmap_no_issues: Geen issues voor deze versie
- label_roadmap_overdue: "%{value} over tijd"
- label_role: Rol
- label_role_and_permissions: Rollen en permissies
- label_role_new: Nieuwe rol
- label_role_plural: Rollen
- label_scm: SCM
- label_search: Zoeken
- label_search_titles_only: Enkel titels doorzoeken
- label_send_information: Stuur accountinformatie naar de gebruiker
- label_send_test_email: Stuur een test e-mail
- label_settings: Instellingen
- label_show_completed_versions: Toon afgeronde versies
- label_sort_by: "Sorteer op %{value}"
- label_sort_higher: Verplaats naar boven
- label_sort_highest: Verplaats naar begin
- label_sort_lower: Verplaats naar beneden
- label_sort_lowest: Verplaats naar eind
- label_spent_time: Gespendeerde tijd
- label_start_to_end: start tot eind
- label_start_to_start: start tot start
- label_statistics: Statistieken
- label_stay_logged_in: Blijf ingelogd
- label_string: Tekst
- label_subproject_plural: Subprojecten
- label_text: Lange tekst
- label_theme: Thema
- label_this_month: deze maand
- label_this_week: deze week
- label_this_year: dit jaar
- label_time_tracking: Tijdregistratie bijhouden
- label_today: vandaag
- label_topic_plural: Onderwerpen
- label_total: Totaal
- label_tracker: Tracker
- label_tracker_new: Nieuwe tracker
- label_tracker_plural: Trackers
- label_updated_time: "%{value} geleden bijgewerkt"
- label_updated_time_by: "%{age} geleden bijgewerkt door %{author}"
- label_used_by: Gebruikt door
- label_user: Gebruiker
- label_user_activity: "%{value}'s activiteit"
- label_user_mail_no_self_notified: Ik wil niet op de hoogte gehouden worden van mijn eigen wijzigingen
- label_user_mail_option_all: "Bij elk gebeurtenis in al mijn projecten..."
- label_user_mail_option_selected: "Enkel bij elke gebeurtenis op het geselecteerde project..."
- label_user_new: Nieuwe gebruiker
- label_user_plural: Gebruikers
- label_version: Versie
- label_version_new: Nieuwe versie
- label_version_plural: Versies
- label_view_diff: Bekijk verschillen
- label_view_revisions: Bekijk revisies
- label_watched_issues: Gemonitorde issues
- label_week: Week
- label_wiki: Wiki
- label_wiki_edit: Wiki edit
- label_wiki_edit_plural: Wiki edits
- label_wiki_page: Wikipagina
- label_wiki_page_plural: Wikipagina's
- label_workflow: Workflow
- label_year: Jaar
- label_yesterday: gisteren
- mail_body_account_activation_request: "Een nieuwe gebruiker (%{value}) is geregistreerd. Zijn account wacht op uw akkoord:"
- mail_body_account_information: Uw account gegevens
- mail_body_account_information_external: "U kunt uw account (%{value}) gebruiken om in te loggen."
- mail_body_lost_password: 'Gebruik de volgende link om uw wachtwoord te wijzigen:'
- mail_body_register: 'Gebruik de volgende link om uw account te activeren:'
- mail_body_reminder: "%{count} issue(s) die aan u toegewezen zijn en voldaan moeten zijn in de komende %{days} dagen:"
- mail_subject_account_activation_request: "%{value} accountactivatieverzoek"
- mail_subject_lost_password: "uw %{value} wachtwoord"
- mail_subject_register: "uw %{value} accountactivatie"
- mail_subject_reminder: "%{count} issue(s) die voldaan moeten zijn in de komende %{days} dagen."
- notice_account_activated: uw account is geactiveerd. u kunt nu inloggen.
- notice_account_invalid_creditentials: Incorrecte gebruikersnaam of wachtwoord
- notice_account_lost_email_sent: Er is een e-mail naar u verstuurd met instructies over het kiezen van een nieuw wachtwoord.
- notice_account_password_updated: Wachtwoord is met succes gewijzigd
- notice_account_pending: "Uw account is aangemaakt, maar wacht nog op goedkeuring van de beheerder."
- notice_account_register_done: Account is met succes aangemaakt.
- notice_account_unknown_email: Onbekende gebruiker.
- notice_account_updated: Account is met succes gewijzigd
- notice_account_wrong_password: Incorrect wachtwoord
- notice_can_t_change_password: Dit account gebruikt een externe bron voor authenticatie. Het is niet mogelijk om het wachtwoord te veranderen.
- notice_default_data_loaded: Standaard configuratie succesvol geladen.
- notice_email_error: "Er is een fout opgetreden tijdens het versturen van (%{value})"
- notice_email_sent: "Een e-mail werd verstuurd naar %{value}"
- notice_failed_to_save_issues: "Fout bij bewaren van %{count} issue(s) (%{total} geselecteerd): %{ids}."
- notice_feeds_access_key_reseted: Je RSS toegangssleutel werd gereset.
- notice_file_not_found: De pagina die u probeerde te benaderen bestaat niet of is verwijderd.
- notice_locking_conflict: De gegevens zijn gewijzigd door een andere gebruiker.
- notice_no_issue_selected: "Er is geen issue geselecteerd. Selecteer de issue die u wilt bewerken."
- notice_not_authorized: Het is u niet toegestaan deze pagina te raadplegen.
- notice_successful_connection: Verbinding succesvol.
- notice_successful_create: Succesvol aangemaakt.
- notice_successful_delete: Succesvol verwijderd.
- notice_successful_update: Wijzigen succesvol.
- notice_unable_delete_version: Niet mogelijk om deze versie te verwijderen.
- permission_add_issue_notes: Voeg notities toe
- permission_add_issue_watchers: Voeg monitors toe
- permission_add_issues: Voeg issues toe
- permission_add_messages: Voeg berichten toe
- permission_browse_repository: Repository doorbladeren
- permission_comment_news: Nieuws commentaar geven
- permission_commit_access: Commit toegang
- permission_delete_issues: Issues verwijderen
- permission_delete_messages: Berichten verwijderen
- permission_delete_own_messages: Eigen berichten verwijderen
- permission_delete_wiki_pages: Wiki pagina's verwijderen
- permission_delete_wiki_pages_attachments: Bijlagen verwijderen
- permission_edit_issue_notes: Notities bewerken
- permission_edit_issues: Issues bewerken
- permission_edit_messages: Berichten bewerken
- permission_edit_own_issue_notes: Eigen notities bewerken
- permission_edit_own_messages: Eigen berichten bewerken
- permission_edit_own_time_entries: Eigen tijdlogboek bewerken
- permission_edit_project: Project bewerken
- permission_edit_time_entries: Tijdlogboek bewerken
- permission_edit_wiki_pages: Wiki pagina's bewerken
- permission_log_time: Gespendeerde tijd loggen
- permission_manage_boards: Forums beheren
- permission_manage_categories: Issue-categorieën beheren
- permission_manage_documents: Documenten beheren
- permission_manage_files: Bestanden beheren
- permission_manage_issue_relations: Issuerelaties beheren
- permission_manage_members: Leden beheren
- permission_manage_news: Nieuws beheren
- permission_manage_public_queries: Publieke queries beheren
- permission_manage_repository: Repository beheren
- permission_manage_versions: Versiebeheer
- permission_manage_wiki: Wikibeheer
- permission_move_issues: Issues verplaatsen
- permission_protect_wiki_pages: Wikipagina's beschermen
- permission_rename_wiki_pages: Wikipagina's hernoemen
- permission_save_queries: Queries opslaan
- permission_select_project_modules: Project modules selecteren
- permission_view_calendar: Kalender bekijken
- permission_view_changesets: Changesets bekijken
- permission_view_documents: Documenten bekijken
- permission_view_files: Bestanden bekijken
- permission_view_gantt: Gantt grafiek bekijken
- permission_view_issue_watchers: Monitorlijst bekijken
- permission_view_messages: Berichten bekijken
- permission_view_time_entries: Gespendeerde tijd bekijken
- permission_view_wiki_edits: Wikihistorie bekijken
- permission_view_wiki_pages: Wikipagina's bekijken
- project_module_boards: Forums
- project_module_documents: Documenten
- project_module_files: Bestanden
- project_module_issue_tracking: Issue tracking
- project_module_news: Nieuws
- project_module_repository: Repository
- project_module_time_tracking: Tijd tracking
- project_module_wiki: Wiki
- setting_activity_days_default: Aantal dagen getoond bij het tabblad "Activiteit"
- setting_app_subtitle: Applicatieondertitel
- setting_app_title: Applicatietitel
- setting_attachment_max_size: Attachment max. grootte
- setting_autofetch_changesets: Haal commits automatisch op
- setting_autologin: Automatisch inloggen
- setting_bcc_recipients: Blind carbon copy ontvangers (bcc)
- setting_commit_fix_keywords: Gefixeerde trefwoorden
- setting_commit_ref_keywords: Refererende trefwoorden
- setting_cross_project_issue_relations: Sta cross-project issuerelaties toe
- setting_date_format: Datumformaat
- setting_default_language: Standaard taal
- setting_default_projects_public: Nieuwe projecten zijn standaard publiek
- setting_diff_max_lines_displayed: Max aantal diff regels weer te geven
- setting_display_subprojects_issues: Standaard issues van subproject tonen
- setting_emails_footer: E-mails footer
- setting_enabled_scm: SCM ingeschakeld
- setting_feeds_limit: Feedinhoudlimiet
- setting_gravatar_enabled: Gebruik Gravatar gebruikersiconen
- setting_host_name: Hostnaam
- setting_issue_list_default_columns: Standaardkolommen getoond op de lijst met issues
- setting_issues_export_limit: Max aantal te exporteren issues
- setting_login_required: Authenticatie vereist
- setting_mail_from: Afzender e-mail adres
- setting_mail_handler_api_enabled: Schakel WS in voor inkomende mail.
- setting_mail_handler_api_key: API sleutel
- setting_per_page_options: Aantal objecten per pagina (opties)
- setting_plain_text_mail: platte tekst (geen HTML)
- setting_protocol: Protocol
- setting_self_registration: Zelfregistratie toegestaan
- setting_sequential_project_identifiers: Genereer sequentiële projectidentiteiten
- setting_sys_api_enabled: Gebruik WS voor repository beheer
- setting_text_formatting: Tekstformaat
- setting_time_format: Tijd formaat
- setting_user_format: Gebruikers weergaveformaat
- setting_welcome_text: Welkomsttekst
- setting_wiki_compression: Wikigeschiedenis comprimeren
- status_active: actief
- status_locked: vergrendeld
- status_registered: geregistreerd
- text_are_you_sure: Weet u het zeker?
- text_assign_time_entries_to_project: Gerapporteerde uren toevoegen aan dit project
- text_caracters_maximum: "%{count} van maximum aantal tekens."
- text_caracters_minimum: "Moet minstens %{count} karakters lang zijn."
- text_comma_separated: Meerdere waarden toegestaan (kommagescheiden).
- text_default_administrator_account_changed: Standaard beheerderaccount gewijzigd
- text_destroy_time_entries: Verwijder gerapporteerde uren
- text_destroy_time_entries_question: "%{hours} uren werden gerapporteerd op de issue(s) die u wilde verwijderen. Wat wil u doen?"
- text_diff_truncated: '... Deze diff werd afgekort omdat het de maximale weer te geven karakters overschreed.'
- text_email_delivery_not_configured: "E-mailbezorging is niet geconfigureerd. Mededelingen zijn uitgeschakeld.\nConfigureer uw SMTP server in config/configuration.yml en herstart de applicatie om dit te activeren."
- text_enumeration_category_reassign_to: 'Wijs de volgende waarde toe:'
- text_enumeration_destroy_question: "%{count} objecten zijn toegewezen aan deze waarde."
- text_file_repository_writable: Bestandsrepository beschrijfbaar
- text_issue_added: "Issue %{id} is gerapporteerd (door %{author})."
- text_issue_category_destroy_assignments: Verwijder toewijzingen aan deze categorie
- text_issue_category_destroy_question: "Er zijn issues (%{count}) aan deze categorie toegewezen. Wat wilt u hiermee doen ?"
- text_issue_category_reassign_to: Issues opnieuw toewijzen aan deze categorie
- text_issue_updated: "Issue %{id} is gewijzigd (door %{author})."
- text_issues_destroy_confirmation: 'Weet u zeker dat u deze issue(s) wil verwijderen?'
- text_issues_ref_in_commit_messages: Opzoeken en aanpassen van issues in commitberichten
- text_length_between: "Lengte tussen %{min} en %{max} tekens."
- text_load_default_configuration: Laad de standaardconfiguratie
- text_min_max_length_info: 0 betekent geen restrictie
- text_no_configuration_data: "Rollen, trackers, issue statussen en workflows zijn nog niet geconfigureerd.\nHet is ten zeerste aangeraden om de standaard configuratie in te laden. U kunt deze aanpassen nadat deze is ingeladen."
- text_plugin_assets_writable: Plugin assets directory beschrijfbaar
- text_project_destroy_confirmation: Weet u zeker dat u dit project en alle gerelateerde gegevens wilt verwijderen?
- text_project_identifier_info: 'kleine letters (a-z), cijfers en liggende streepjes toegestaan. Eenmaal bewaard kan de identificatiecode niet meer worden gewijzigd.'
- text_reassign_time_entries: 'Gerapporteerde uren opnieuw toewijzen:'
- text_regexp_info: bv. ^[A-Z0-9]+$
- text_repository_usernames_mapping: "Koppel de Redminegebruikers aan gebruikers in de repository log.\nGebruikers met dezelfde Redmine en repository gebruikersnaam of email worden automatisch gekoppeld."
- text_rmagick_available: RMagick beschikbaar (optioneel)
- text_select_mail_notifications: Selecteer acties waarvoor mededelingen via mail moeten worden verstuurd.
- text_select_project_modules: 'Selecteer de modules die u wilt gebruiken voor dit project:'
- text_status_changed_by_changeset: "Toegepast in changeset %{value}."
- text_subprojects_destroy_warning: "De subprojecten: %{value} zullen ook verwijderd worden."
- text_tip_issue_begin_day: issue die op deze dag begint
- text_tip_issue_begin_end_day: issue die op deze dag begint en eindigt
- text_tip_issue_end_day: issue die op deze dag eindigt
- text_tracker_no_workflow: Geen workflow gedefinieerd voor deze tracker
- text_unallowed_characters: Niet toegestane tekens
- text_user_mail_option: "Bij niet-geselecteerde projecten zult u enkel mededelingen ontvangen voor issues die u monitort of waar u bij betrokken bent (als auteur of toegewezen persoon)."
- text_user_wrote: "%{value} schreef:"
- text_wiki_destroy_confirmation: Weet u zeker dat u deze wiki en zijn inhoud wenst te verwijderen?
- text_workflow_edit: Selecteer een rol en een tracker om de workflow te wijzigen
- warning_attachments_not_saved: "%{count} bestand(en) konden niet opgeslagen worden."
- button_create_and_continue: Maak en ga verder
- text_custom_field_possible_values_info: 'Per lijn een waarde'
- label_display: Toon
- field_editable: Bewerkbaar
- setting_repository_log_display_limit: Max aantal revisies zichbaar
- setting_file_max_size_displayed: Max grootte van tekst bestanden inline zichtbaar
- field_watcher: Watcher
- setting_openid: Sta OpenID login en registratie toe
- field_identity_url: OpenID URL
- label_login_with_open_id_option: of login met je OpenID
- field_content: Content
- label_descending: Aflopend
- label_sort: Sorteer
- label_ascending: Oplopend
- label_date_from_to: Van %{start} tot %{end}
- label_greater_or_equal: ">="
- label_less_or_equal: <=
- text_wiki_page_destroy_question: Deze pagina heeft %{descendants} subpagina's en onderliggende pagina's?. Wat wilt u hiermee doen?
- text_wiki_page_reassign_children: Alle subpagina's toewijzen aan deze hoofdpagina
- text_wiki_page_nullify_children: Behoud subpagina's als hoofdpagina's
- text_wiki_page_destroy_children: Verwijder alle subpagina's en onderliggende pagina's
- setting_password_min_length: Minimum wachtwoord lengte
- field_group_by: Groepeer resultaten per
- mail_subject_wiki_content_updated: "'%{id}' wiki pagina is bijgewerkt"
- label_wiki_content_added: Wiki pagina toegevoegd
- mail_subject_wiki_content_added: "'%{id}' wiki pagina is toegevoegd"
- mail_body_wiki_content_added: De '%{id}' wiki pagina is toegevoegd door %{author}.
- label_wiki_content_updated: Wiki pagina bijgewerkt
- mail_body_wiki_content_updated: De '%{id}' wiki pagina is bijgewerkt door %{author}.
- permission_add_project: Maak project
- setting_new_project_user_role_id: Rol van gebruiker die een project maakt
- label_view_all_revisions: Bekijk alle revisies
- label_tag: Tag
- label_branch: Branch
- error_no_tracker_in_project: Geen tracker is geassocieerd met dit project. Check de project instellingen.
- error_no_default_issue_status: Geen standaard issue status ingesteld. Check de configuratie (Ga naar "Administratie -> Issue statussen").
- text_journal_changed: "%{label} gewijzigd van %{old} naar %{new}"
- text_journal_set_to: "%{label} gewijzigd naar %{value}"
- text_journal_deleted: "%{label} verwijderd (%{old})"
- label_group_plural: Groepen
- label_group: Groep
- label_group_new: Nieuwe groep
- label_time_entry_plural: Bestede tijd
- text_journal_added: "%{label} %{value} toegevoegd"
- field_active: Actief
- enumeration_system_activity: Systeem Activiteit
- permission_delete_issue_watchers: Verwijder volgers
- version_status_closed: gesloten
- version_status_locked: vergrendeld
- version_status_open: open
- error_can_not_reopen_issue_on_closed_version: Een issue toegewezen aan een gesloten versie kan niet heropend worden
- label_user_anonymous: Anoniem
- button_move_and_follow: Verplaats en volg
- setting_default_projects_modules: Standaard geactiveerde modules voor nieuwe projecten
- setting_gravatar_default: Standaard Gravatar plaatje
- field_sharing: Delen
- label_version_sharing_hierarchy: Met project hiërarchie
- label_version_sharing_system: Met alle projecten
- label_version_sharing_descendants: Met subprojecten
- label_version_sharing_tree: Met project boom
- label_version_sharing_none: Niet gedeeld
- error_can_not_archive_project: Dit project kan niet worden gearchiveerd
- button_duplicate: Dupliceer
- button_copy_and_follow: Kopiëer en volg
- label_copy_source: Bron
- setting_issue_done_ratio: Bereken issue percentage voldaan met
- setting_issue_done_ratio_issue_status: Gebruik de issue status
- error_issue_done_ratios_not_updated: Issue percentage voldaan niet geupdate.
- error_workflow_copy_target: Selecteer tracker(s) en rol(len)
- setting_issue_done_ratio_issue_field: Gebruik het issue veld
- label_copy_same_as_target: Zelfde als doel
- label_copy_target: Doel
- notice_issue_done_ratios_updated: Issue percentage voldaan geupdate.
- error_workflow_copy_source: Selecteer een bron tracker of rol
- label_update_issue_done_ratios: Update issue percentage voldaan
- setting_start_of_week: Week begint op
- permission_view_issues: Bekijk Issues
- label_display_used_statuses_only: Laat alleen statussen zien die gebruikt worden door deze tracker
- label_revision_id: Revisie %{value}
- label_api_access_key: API access key
- label_api_access_key_created_on: API access key gemaakt %{value} geleden
- label_feeds_access_key: RSS access key
- notice_api_access_key_reseted: Uw API access key was gereset.
- setting_rest_api_enabled: Activeer REST web service
- label_missing_api_access_key: Geen API access key
- label_missing_feeds_access_key: Geen RSS access key
- button_show: Laat zien
- text_line_separated: Meerdere waarden toegestaan (elke regel is een waarde).
- setting_mail_handler_body_delimiters: Breek email verwerking af na een van deze regels
- permission_add_subprojects: Maak subprojecten
- label_subproject_new: Nieuw subproject
- text_own_membership_delete_confirmation: |-
- U staat op punt om sommige of alle van uw permissies te verwijderen en bent mogelijk niet meer toegestaan om dit project hierna te wijzigen.
- Wilt u doorgaan?
- label_close_versions: Sluit complete versies
- label_board_sticky: Sticky
- label_board_locked: Vergrendeld
- permission_export_wiki_pages: Exporteer wiki pagina's
- setting_cache_formatted_text: Cache opgemaakte tekst
- permission_manage_project_activities: Beheer project activiteiten
- error_unable_delete_issue_status: Verwijderen van issue status niet gelukt
- label_profile: Profiel
- permission_manage_subtasks: Beheer subtasks
- field_parent_issue: Parent task
- label_subtask_plural: Subtasks
- label_project_copy_notifications: Stuur email notificaties voor de project kopie
- error_can_not_delete_custom_field: Verwijderen niet mogelijk van custom field
- error_unable_to_connect: Geen connectie (%{value})
- error_can_not_remove_role: Deze rol is in gebruik en kan niet worden verwijderd.
- error_can_not_delete_tracker: Deze tracker bevat nog issues en kan niet worden verwijderd.
- field_principal: Principal
- label_my_page_block: Mijn pagina block
- notice_failed_to_save_members: "Niet gelukt om lid/leden op te slaan: %{errors}."
- text_zoom_out: Zoom uit
- text_zoom_in: Zoom in
- notice_unable_delete_time_entry: Verwijderen niet mogelijk van tijd log invoer.
- label_overall_spent_time: Totaal bestede tijd
- field_time_entries: Registreer tijd
- project_module_gantt: Gantt
- project_module_calendar: Kalender
- button_edit_associated_wikipage: "Bewerk bijbehorende wiki pagina: %{page_title}"
- text_are_you_sure_with_children: Verwijder issue en alle onderliggende issues?
- field_text: Tekst veld
- label_user_mail_option_only_owner: Alleen voor dingen waarvan ik de auteur ben
- setting_default_notification_option: Standaard instelling voor mededelingen
- label_user_mail_option_only_my_events: Alleen voor dingen die ik volg of bij betrokken ben
- label_user_mail_option_only_assigned: Alleen voor dingen die aan mij zijn toegewezen
- label_user_mail_option_none: Bij geen enkele gebeurtenis
- field_member_of_group: Groep van toegewezene
- field_assigned_to_role: Rol van toegewezene
- notice_not_authorized_archived_project: Het project dat u wilt bezoeken is gearchiveerd.
- label_principal_search: "Zoek naar gebruiker of groep:"
- label_user_search: "Zoek naar gebruiker:"
- field_visible: Zichtbaar
- setting_emails_header: Emails header
- setting_commit_logtime_activity_id: Standaard activiteit voor tijdregistratie
- text_time_logged_by_changeset: Toegepast in changeset %{value}.
- setting_commit_logtime_enabled: Activeer tijdregistratie
- notice_gantt_chart_truncated: De gantt chart is ingekort omdat het meer objecten bevat dan kan worden weergegeven, (%{max})
- setting_gantt_items_limit: Max. aantal objecten op gantt chart
- field_warn_on_leaving_unsaved: Waarschuw me wanneer ik een pagina verlaat waarvan de tekst niet opgeslagen is
- text_warn_on_leaving_unsaved: De huidige pagina bevat tekst die niet is opgeslagen en dit zal verloren gaan als u deze pagina nu verlaat.
- label_my_queries: Mijn aangepaste zoekopdrachten
- text_journal_changed_no_detail: "%{label} updated"
- label_news_comment_added: Commentaar toegevoegd aan een nieuwsitem
- button_expand_all: Klap uit
- button_collapse_all: Klap in
- label_additional_workflow_transitions_for_assignee: Aanvullende veranderingen toegestaan wanneer de gebruiker de toegewezene is
- label_additional_workflow_transitions_for_author: Aanvullende veranderingen toegestaan wanneer de gebruiker de auteur is
- label_bulk_edit_selected_time_entries: Bulk edit selected time entries
- text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)?
- label_role_anonymous: Anonymous
- label_role_non_member: Non member
- label_issue_note_added: Note added
- label_issue_status_updated: Status updated
- label_issue_priority_updated: Priority updated
- label_issues_visibility_own: Issues created by or assigned to the user
- field_issues_visibility: Issues visibility
- label_issues_visibility_all: All issues
- permission_set_own_issues_private: Set own issues public or private
- field_is_private: Private
- permission_set_issues_private: Set issues public or private
- label_issues_visibility_public: All non private issues
- text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s).
- field_commit_logs_encoding: Encodering van commit berichten
- field_scm_path_encoding: Path encoding
- text_scm_path_encoding_note: "Standaard: UTF-8"
- field_path_to_repository: Path to repository
- field_root_directory: Root directory
- field_cvs_module: Module
- field_cvsroot: CVSROOT
- text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo)
- text_scm_command: Command
- text_scm_command_version: Version
- label_git_report_last_commit: Report last commit for files and directories
- text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it.
- text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel.
- notice_issue_successful_create: Issue %{id} created.
- label_between: between
- setting_issue_group_assignment: Allow issue assignment to groups
- label_diff: diff
- text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo)
- description_query_sort_criteria_direction: Sort direction
- description_project_scope: Search scope
- description_filter: Filter
- description_user_mail_notification: Mail notification settings
- description_date_from: Enter start date
- description_message_content: Message content
- description_available_columns: Available Columns
- description_date_range_interval: Choose range by selecting start and end date
- description_issue_category_reassign: Choose issue category
- description_search: Searchfield
- description_notes: Notes
- description_date_range_list: Choose range from list
- description_choose_project: Projects
- description_date_to: Enter end date
- description_query_sort_criteria_attribute: Sort attribute
- description_wiki_subpages_reassign: Choose new parent page
- description_selected_columns: Selected Columns
- label_parent_revision: Parent
- label_child_revision: Child
- error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size.
- setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues
- button_edit_section: Edit this section
- setting_repositories_encodings: Attachments and repositories encodings
- description_all_columns: All Columns
- button_export: Export
- label_export_options: "%{export_format} export options"
- error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/9a/9a661f1b4311fa0f11b854a9105322a60611a794.svn-base
--- a/.svn/pristine/9a/9a661f1b4311fa0f11b854a9105322a60611a794.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,269 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require 'iconv'
-
-class Changeset < ActiveRecord::Base
- belongs_to :repository
- belongs_to :user
- has_many :changes, :dependent => :delete_all
- has_and_belongs_to_many :issues
- has_and_belongs_to_many :parents,
- :class_name => "Changeset",
- :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
- :association_foreign_key => 'parent_id', :foreign_key => 'changeset_id'
- has_and_belongs_to_many :children,
- :class_name => "Changeset",
- :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
- :association_foreign_key => 'changeset_id', :foreign_key => 'parent_id'
-
- acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
- :description => :long_comments,
- :datetime => :committed_on,
- :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :rev => o.identifier}}
-
- acts_as_searchable :columns => 'comments',
- :include => {:repository => :project},
- :project_key => "#{Repository.table_name}.project_id",
- :date_column => 'committed_on'
-
- acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
- :author_key => :user_id,
- :find_options => {:include => [:user, {:repository => :project}]}
-
- validates_presence_of :repository_id, :revision, :committed_on, :commit_date
- validates_uniqueness_of :revision, :scope => :repository_id
- validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
-
- named_scope :visible, lambda {|*args| { :include => {:repository => :project},
- :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
-
- after_create :scan_for_issues
- before_create :before_create_cs
-
- def revision=(r)
- write_attribute :revision, (r.nil? ? nil : r.to_s)
- end
-
- # Returns the identifier of this changeset; depending on repository backends
- def identifier
- if repository.class.respond_to? :changeset_identifier
- repository.class.changeset_identifier self
- else
- revision.to_s
- end
- end
-
- def committed_on=(date)
- self.commit_date = date
- super
- end
-
- # Returns the readable identifier
- def format_identifier
- if repository.class.respond_to? :format_changeset_identifier
- repository.class.format_changeset_identifier self
- else
- identifier
- end
- end
-
- def project
- repository.project
- end
-
- def author
- user || committer.to_s.split('<').first
- end
-
- def before_create_cs
- self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
- self.comments = self.class.normalize_comments(
- self.comments, repository.repo_log_encoding)
- self.user = repository.find_committer_user(self.committer)
- end
-
- def scan_for_issues
- scan_comment_for_issue_ids
- end
-
- TIMELOG_RE = /
- (
- ((\d+)(h|hours?))((\d+)(m|min)?)?
- |
- ((\d+)(h|hours?|m|min))
- |
- (\d+):(\d+)
- |
- (\d+([\.,]\d+)?)h?
- )
- /x
-
- def scan_comment_for_issue_ids
- return if comments.blank?
- # keywords used to reference issues
- ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
- ref_keywords_any = ref_keywords.delete('*')
- # keywords used to fix issues
- fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
-
- kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
-
- referenced_issues = []
-
- comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match|
- action, refs = match[2], match[3]
- next unless action.present? || ref_keywords_any
-
- refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m|
- issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2]
- if issue
- referenced_issues << issue
- fix_issue(issue) if fix_keywords.include?(action.to_s.downcase)
- log_time(issue, hours) if hours && Setting.commit_logtime_enabled?
- end
- end
- end
-
- referenced_issues.uniq!
- self.issues = referenced_issues unless referenced_issues.empty?
- end
-
- def short_comments
- @short_comments || split_comments.first
- end
-
- def long_comments
- @long_comments || split_comments.last
- end
-
- def text_tag
- if scmid?
- "commit:#{scmid}"
- else
- "r#{revision}"
- end
- end
-
- # Returns the previous changeset
- def previous
- @previous ||= Changeset.find(:first,
- :conditions => ['id < ? AND repository_id = ?',
- self.id, self.repository_id],
- :order => 'id DESC')
- end
-
- # Returns the next changeset
- def next
- @next ||= Changeset.find(:first,
- :conditions => ['id > ? AND repository_id = ?',
- self.id, self.repository_id],
- :order => 'id ASC')
- end
-
- # Creates a new Change from it's common parameters
- def create_change(change)
- Change.create(:changeset => self,
- :action => change[:action],
- :path => change[:path],
- :from_path => change[:from_path],
- :from_revision => change[:from_revision])
- end
-
- private
-
- # Finds an issue that can be referenced by the commit message
- # i.e. an issue that belong to the repository project, a subproject or a parent project
- def find_referenced_issue_by_id(id)
- return nil if id.blank?
- issue = Issue.find_by_id(id.to_i, :include => :project)
- if issue
- unless issue.project &&
- (project == issue.project || project.is_ancestor_of?(issue.project) ||
- project.is_descendant_of?(issue.project))
- issue = nil
- end
- end
- issue
- end
-
- def fix_issue(issue)
- status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
- if status.nil?
- logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
- return issue
- end
-
- # the issue may have been updated by the closure of another one (eg. duplicate)
- issue.reload
- # don't change the status is the issue is closed
- return if issue.status && issue.status.is_closed?
-
- journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag))
- issue.status = status
- unless Setting.commit_fix_done_ratio.blank?
- issue.done_ratio = Setting.commit_fix_done_ratio.to_i
- end
- Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
- { :changeset => self, :issue => issue })
- unless issue.save
- logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger
- end
- issue
- end
-
- def log_time(issue, hours)
- time_entry = TimeEntry.new(
- :user => user,
- :hours => hours,
- :issue => issue,
- :spent_on => commit_date,
- :comments => l(:text_time_logged_by_changeset, :value => text_tag,
- :locale => Setting.default_language)
- )
- time_entry.activity = log_time_activity unless log_time_activity.nil?
-
- unless time_entry.save
- logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger
- end
- time_entry
- end
-
- def log_time_activity
- if Setting.commit_logtime_activity_id.to_i > 0
- TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i)
- end
- end
-
- def split_comments
- comments =~ /\A(.+?)\r?\n(.*)$/m
- @short_comments = $1 || comments
- @long_comments = $2.to_s.strip
- return @short_comments, @long_comments
- end
-
- public
-
- # Strips and reencodes a commit log before insertion into the database
- def self.normalize_comments(str, encoding)
- Changeset.to_utf8(str.to_s.strip, encoding)
- end
-
- def self.to_utf8(str, encoding)
- Redmine::CodesetUtil.to_utf8(str, encoding)
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/9d/9de0981c528be3c395629de4fb2f38d49f57b9ed.svn-base
--- a/.svn/pristine/9d/9de0981c528be3c395629de4fb2f38d49f57b9ed.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,399 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require File.expand_path('../../test_helper', __FILE__)
-
-class ChangesetTest < ActiveSupport::TestCase
- fixtures :projects, :repositories,
- :issues, :issue_statuses, :issue_categories,
- :changesets, :changes,
- :enumerations,
- :custom_fields, :custom_values,
- :users, :members, :member_roles, :trackers,
- :enabled_modules, :roles
-
- def setup
- end
-
- def test_ref_keywords_any
- ActionMailer::Base.deliveries.clear
- Setting.commit_fix_status_id = IssueStatus.find(
- :first, :conditions => ["is_closed = ?", true]).id
- Setting.commit_fix_done_ratio = '90'
- Setting.commit_ref_keywords = '*'
- Setting.commit_fix_keywords = 'fixes , closes'
-
- c = Changeset.new(:repository => Project.find(1).repository,
- :committed_on => Time.now,
- :comments => 'New commit (#2). Fixes #1',
- :revision => '12345')
- assert c.save
- assert_equal [1, 2], c.issue_ids.sort
- fixed = Issue.find(1)
- assert fixed.closed?
- assert_equal 90, fixed.done_ratio
- assert_equal 1, ActionMailer::Base.deliveries.size
- end
-
- def test_ref_keywords
- Setting.commit_ref_keywords = 'refs'
- Setting.commit_fix_keywords = ''
- c = Changeset.new(:repository => Project.find(1).repository,
- :committed_on => Time.now,
- :comments => 'Ignores #2. Refs #1',
- :revision => '12345')
- assert c.save
- assert_equal [1], c.issue_ids.sort
- end
-
- def test_ref_keywords_any_only
- Setting.commit_ref_keywords = '*'
- Setting.commit_fix_keywords = ''
- c = Changeset.new(:repository => Project.find(1).repository,
- :committed_on => Time.now,
- :comments => 'Ignores #2. Refs #1',
- :revision => '12345')
- assert c.save
- assert_equal [1, 2], c.issue_ids.sort
- end
-
- def test_ref_keywords_any_with_timelog
- Setting.commit_ref_keywords = '*'
- Setting.commit_logtime_enabled = '1'
-
- {
- '2' => 2.0,
- '2h' => 2.0,
- '2hours' => 2.0,
- '15m' => 0.25,
- '15min' => 0.25,
- '3h15' => 3.25,
- '3h15m' => 3.25,
- '3h15min' => 3.25,
- '3:15' => 3.25,
- '3.25' => 3.25,
- '3.25h' => 3.25,
- '3,25' => 3.25,
- '3,25h' => 3.25,
- }.each do |syntax, expected_hours|
- c = Changeset.new(:repository => Project.find(1).repository,
- :committed_on => 24.hours.ago,
- :comments => "Worked on this issue #1 @#{syntax}",
- :revision => '520',
- :user => User.find(2))
- assert_difference 'TimeEntry.count' do
- c.scan_comment_for_issue_ids
- end
- assert_equal [1], c.issue_ids.sort
-
- time = TimeEntry.first(:order => 'id desc')
- assert_equal 1, time.issue_id
- assert_equal 1, time.project_id
- assert_equal 2, time.user_id
- assert_equal expected_hours, time.hours,
- "@#{syntax} should be logged as #{expected_hours} hours but was #{time.hours}"
- assert_equal Date.yesterday, time.spent_on
- assert time.activity.is_default?
- assert time.comments.include?('r520'),
- "r520 was expected in time_entry comments: #{time.comments}"
- end
- end
-
- def test_ref_keywords_closing_with_timelog
- Setting.commit_fix_status_id = IssueStatus.find(
- :first, :conditions => ["is_closed = ?", true]).id
- Setting.commit_ref_keywords = '*'
- Setting.commit_fix_keywords = 'fixes , closes'
- Setting.commit_logtime_enabled = '1'
-
- c = Changeset.new(:repository => Project.find(1).repository,
- :committed_on => Time.now,
- :comments => 'This is a comment. Fixes #1 @4.5, #2 @1',
- :user => User.find(2))
- assert_difference 'TimeEntry.count', 2 do
- c.scan_comment_for_issue_ids
- end
-
- assert_equal [1, 2], c.issue_ids.sort
- assert Issue.find(1).closed?
- assert Issue.find(2).closed?
-
- times = TimeEntry.all(:order => 'id desc', :limit => 2)
- assert_equal [1, 2], times.collect(&:issue_id).sort
- end
-
- def test_ref_keywords_any_line_start
- Setting.commit_ref_keywords = '*'
- c = Changeset.new(:repository => Project.find(1).repository,
- :committed_on => Time.now,
- :comments => '#1 is the reason of this commit',
- :revision => '12345')
- assert c.save
- assert_equal [1], c.issue_ids.sort
- end
-
- def test_ref_keywords_allow_brackets_around_a_issue_number
- Setting.commit_ref_keywords = '*'
- c = Changeset.new(:repository => Project.find(1).repository,
- :committed_on => Time.now,
- :comments => '[#1] Worked on this issue',
- :revision => '12345')
- assert c.save
- assert_equal [1], c.issue_ids.sort
- end
-
- def test_ref_keywords_allow_brackets_around_multiple_issue_numbers
- Setting.commit_ref_keywords = '*'
- c = Changeset.new(:repository => Project.find(1).repository,
- :committed_on => Time.now,
- :comments => '[#1 #2, #3] Worked on these',
- :revision => '12345')
- assert c.save
- assert_equal [1,2,3], c.issue_ids.sort
- end
-
- def test_commit_referencing_a_subproject_issue
- c = Changeset.new(:repository => Project.find(1).repository,
- :committed_on => Time.now,
- :comments => 'refs #5, a subproject issue',
- :revision => '12345')
- assert c.save
- assert_equal [5], c.issue_ids.sort
- assert c.issues.first.project != c.project
- end
-
- def test_commit_referencing_a_parent_project_issue
- # repository of child project
- r = Repository::Subversion.create!(
- :project => Project.find(3),
- :url => 'svn://localhost/test')
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :comments => 'refs #2, an issue of a parent project',
- :revision => '12345')
- assert c.save
- assert_equal [2], c.issue_ids.sort
- assert c.issues.first.project != c.project
- end
-
- def test_text_tag_revision
- c = Changeset.new(:revision => '520')
- assert_equal 'r520', c.text_tag
- end
-
- def test_text_tag_hash
- c = Changeset.new(
- :scmid => '7234cb2750b63f47bff735edc50a1c0a433c2518',
- :revision => '7234cb2750b63f47bff735edc50a1c0a433c2518')
- assert_equal 'commit:7234cb2750b63f47bff735edc50a1c0a433c2518', c.text_tag
- end
-
- def test_text_tag_hash_all_number
- c = Changeset.new(:scmid => '0123456789', :revision => '0123456789')
- assert_equal 'commit:0123456789', c.text_tag
- end
-
- def test_previous
- changeset = Changeset.find_by_revision('3')
- assert_equal Changeset.find_by_revision('2'), changeset.previous
- end
-
- def test_previous_nil
- changeset = Changeset.find_by_revision('1')
- assert_nil changeset.previous
- end
-
- def test_next
- changeset = Changeset.find_by_revision('2')
- assert_equal Changeset.find_by_revision('3'), changeset.next
- end
-
- def test_next_nil
- changeset = Changeset.find_by_revision('10')
- assert_nil changeset.next
- end
-
- def test_comments_should_be_converted_to_utf8
- proj = Project.find(3)
- # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
- str = "Texte encod\xe9 en ISO-8859-1."
- str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
- r = Repository::Bazaar.create!(
- :project => proj,
- :url => '/tmp/test/bazaar',
- :log_encoding => 'ISO-8859-1' )
- assert r
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :revision => '123',
- :scmid => '12345',
- :comments => str)
- assert( c.save )
- str_utf8 = "Texte encod\xc3\xa9 en ISO-8859-1."
- str_utf8.force_encoding("UTF-8") if str_utf8.respond_to?(:force_encoding)
- assert_equal str_utf8, c.comments
- end
-
- def test_invalid_utf8_sequences_in_comments_should_be_replaced_latin1
- proj = Project.find(3)
- # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
- str1 = "Texte encod\xe9 en ISO-8859-1."
- str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
- str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
- str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
- r = Repository::Bazaar.create!(
- :project => proj,
- :url => '/tmp/test/bazaar',
- :log_encoding => 'UTF-8' )
- assert r
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :revision => '123',
- :scmid => '12345',
- :comments => str1,
- :committer => str2)
- assert( c.save )
- assert_equal "Texte encod? en ISO-8859-1.", c.comments
- assert_equal "?a?b?c?d?e test", c.committer
- end
-
- def test_invalid_utf8_sequences_in_comments_should_be_replaced_ja_jis
- proj = Project.find(3)
- str = "test\xb5\xfetest\xb5\xfe"
- if str.respond_to?(:force_encoding)
- str.force_encoding('ASCII-8BIT')
- end
- r = Repository::Bazaar.create!(
- :project => proj,
- :url => '/tmp/test/bazaar',
- :log_encoding => 'ISO-2022-JP' )
- assert r
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :revision => '123',
- :scmid => '12345',
- :comments => str)
- assert( c.save )
- assert_equal "test??test??", c.comments
- end
-
- def test_comments_should_be_converted_all_latin1_to_utf8
- s1 = "\xC2\x80"
- s2 = "\xc3\x82\xc2\x80"
- s4 = s2.dup
- if s1.respond_to?(:force_encoding)
- s3 = s1.dup
- s1.force_encoding('ASCII-8BIT')
- s2.force_encoding('ASCII-8BIT')
- s3.force_encoding('ISO-8859-1')
- s4.force_encoding('UTF-8')
- assert_equal s3.encode('UTF-8'), s4
- end
- proj = Project.find(3)
- r = Repository::Bazaar.create!(
- :project => proj,
- :url => '/tmp/test/bazaar',
- :log_encoding => 'ISO-8859-1' )
- assert r
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :revision => '123',
- :scmid => '12345',
- :comments => s1)
- assert( c.save )
- assert_equal s4, c.comments
- end
-
- def test_invalid_utf8_sequences_in_paths_should_be_replaced
- proj = Project.find(3)
- str1 = "Texte encod\xe9 en ISO-8859-1"
- str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
- str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
- str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
- r = Repository::Bazaar.create!(
- :project => proj,
- :url => '/tmp/test/bazaar',
- :log_encoding => 'UTF-8' )
- assert r
- cs = Changeset.new(
- :repository => r,
- :committed_on => Time.now,
- :revision => '123',
- :scmid => '12345',
- :comments => "test")
- assert(cs.save)
- ch = Change.new(
- :changeset => cs,
- :action => "A",
- :path => str1,
- :from_path => str2,
- :from_revision => "345")
- assert(ch.save)
- assert_equal "Texte encod? en ISO-8859-1", ch.path
- assert_equal "?a?b?c?d?e test", ch.from_path
- end
-
- def test_comments_nil
- proj = Project.find(3)
- r = Repository::Bazaar.create!(
- :project => proj,
- :url => '/tmp/test/bazaar',
- :log_encoding => 'ISO-8859-1' )
- assert r
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :revision => '123',
- :scmid => '12345',
- :comments => nil,
- :committer => nil)
- assert( c.save )
- assert_equal "", c.comments
- assert_equal nil, c.committer
- if c.comments.respond_to?(:force_encoding)
- assert_equal "UTF-8", c.comments.encoding.to_s
- end
- end
-
- def test_comments_empty
- proj = Project.find(3)
- r = Repository::Bazaar.create!(
- :project => proj,
- :url => '/tmp/test/bazaar',
- :log_encoding => 'ISO-8859-1' )
- assert r
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :revision => '123',
- :scmid => '12345',
- :comments => "",
- :committer => "")
- assert( c.save )
- assert_equal "", c.comments
- assert_equal "", c.committer
- if c.comments.respond_to?(:force_encoding)
- assert_equal "UTF-8", c.comments.encoding.to_s
- assert_equal "UTF-8", c.committer.encoding.to_s
- end
- end
-
- def test_identifier
- c = Changeset.find_by_revision('1')
- assert_equal c.revision, c.identifier
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/9e/9e5619582de675b0ecdf014e7d0f6086b43824e8.svn-base
--- a/.svn/pristine/9e/9e5619582de675b0ecdf014e7d0f6086b43824e8.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-module SettingsHelper
- def administration_settings_tabs
- tabs = [{:name => 'general', :partial => 'settings/general', :label => :label_general},
- {:name => 'display', :partial => 'settings/display', :label => :label_display},
- {:name => 'authentication', :partial => 'settings/authentication', :label => :label_authentication},
- {:name => 'projects', :partial => 'settings/projects', :label => :label_project_plural},
- {:name => 'issues', :partial => 'settings/issues', :label => :label_issue_tracking},
- {:name => 'notifications', :partial => 'settings/notifications', :label => :field_mail_notification},
- {:name => 'mail_handler', :partial => 'settings/mail_handler', :label => :label_incoming_emails},
- {:name => 'repositories', :partial => 'settings/repositories', :label => :label_repository_plural}
- ]
- end
-
- def setting_select(setting, choices, options={})
- if blank_text = options.delete(:blank)
- choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices
- end
- setting_label(setting, options).html_safe +
- select_tag("settings[#{setting}]",
- options_for_select(choices, Setting.send(setting).to_s),
- options).html_safe
- end
-
- def setting_multiselect(setting, choices, options={})
- setting_values = Setting.send(setting)
- setting_values = [] unless setting_values.is_a?(Array)
-
- setting_label(setting, options).html_safe +
- hidden_field_tag("settings[#{setting}][]", '').html_safe +
- choices.collect do |choice|
- text, value = (choice.is_a?(Array) ? choice : [choice, choice])
- content_tag(
- 'label',
- check_box_tag(
- "settings[#{setting}][]",
- value,
- Setting.send(setting).include?(value)
- ) + text.to_s,
- :class => 'block'
- )
- end.join.html_safe
- end
-
- def setting_text_field(setting, options={})
- setting_label(setting, options).html_safe +
- text_field_tag("settings[#{setting}]", Setting.send(setting), options).html_safe
- end
-
- def setting_text_area(setting, options={})
- setting_label(setting, options).html_safe +
- text_area_tag("settings[#{setting}]", Setting.send(setting), options).html_safe
- end
-
- def setting_check_box(setting, options={})
- setting_label(setting, options).html_safe +
- hidden_field_tag("settings[#{setting}]", 0).html_safe +
- check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options).html_safe
- end
-
- def setting_label(setting, options={})
- label = options.delete(:label)
- label != false ? content_tag("label", l(label || "setting_#{setting}")).html_safe : ''
- end
-
- # Renders a notification field for a Redmine::Notifiable option
- def notification_field(notifiable)
- return content_tag(:label,
- check_box_tag('settings[notified_events][]',
- notifiable.name,
- Setting.notified_events.include?(notifiable.name)).html_safe +
- l_or_humanize(notifiable.name, :prefix => 'label_').html_safe,
- :class => notifiable.parent.present? ? "parent" : '').html_safe
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/9f/9ff0a6b6fe2dd5058c95cd5e523c0f947b15934a.svn-base
--- a/.svn/pristine/9f/9ff0a6b6fe2dd5058c95cd5e523c0f947b15934a.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-class Group < Principal
- generator_for :lastname, :start => 'Group'
-
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/a0/a0fde97b5566af05f8292290fc6fa97613507ae9.svn-base
--- a/.svn/pristine/a0/a0fde97b5566af05f8292290fc6fa97613507ae9.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-class TimeEntry < ActiveRecord::Base
- generator_for(:spent_on) { Date.today }
- generator_for(:hours) { (rand * 10).round(2) } # 0.01 to 9.99
- generator_for :user, :method => :generate_user
-
- def self.generate_user
- User.generate_with_protected!
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/a3/a3d7c35759f83e88ae49f41feed90857719a03ad.svn-base
--- a/.svn/pristine/a3/a3d7c35759f83e88ae49f41feed90857719a03ad.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-
-<% if User.current.allowed_to?(:manage_issue_relations, @project) %>
- <%= toggle_link l(:button_add), 'new-relation-form', {:focus => 'relation_issue_to_id'} %>
-<% end %>
-
-
-<%=l(:label_related_issues)%>
-
-<% if @relations.present? %>
-
-<% end %>
-
-<% remote_form_for(:relation, @relation,
- :url => {:controller => 'issue_relations', :action => 'create', :issue_id => @issue},
- :method => :post,
- :complete => "Form.Element.focus('relation_issue_to_id');",
- :html => {:id => 'new-relation-form', :style => (@relation ? '' : 'display: none;')}) do |f| %>
-<%= render :partial => 'issue_relations/form', :locals => {:f => f}%>
-<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/a5/a5766013768a71e99092a265b9e09c7b5e0e3333.svn-base
--- a/.svn/pristine/a5/a5766013768a71e99092a265b9e09c7b5e0e3333.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,475 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require 'ar_condition'
-
-class Mailer < ActionMailer::Base
- layout 'mailer'
- helper :application
- helper :issues
- helper :custom_fields
-
- include ActionController::UrlWriter
- include Redmine::I18n
-
- def self.default_url_options
- h = Setting.host_name
- h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
- { :host => h, :protocol => Setting.protocol }
- end
-
- # Builds a tmail object used to email recipients of the added issue.
- #
- # Example:
- # issue_add(issue) => tmail object
- # Mailer.deliver_issue_add(issue) => sends an email to issue recipients
- def issue_add(issue)
- 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
- recipients issue.recipients
- cc(issue.watcher_recipients - @recipients)
- subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
- body :issue => issue,
- :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
- render_multipart('issue_add', body)
- end
-
- # Builds a tmail object used to email recipients of the edited issue.
- #
- # Example:
- # issue_edit(journal) => tmail object
- # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients
- def issue_edit(journal)
- issue = journal.journalized.reload
- 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 journal
- references issue
- @author = journal.user
- recipients issue.recipients
- # Watchers in cc
- cc(issue.watcher_recipients - @recipients)
- s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
- s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
- s << issue.subject
- subject s
- body :issue => issue,
- :journal => journal,
- :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
-
- render_multipart('issue_edit', body)
- end
-
- def reminder(user, issues, days)
- set_language_if_valid user.language
- recipients user.mail
- subject l(:mail_subject_reminder, :count => issues.size, :days => days)
- body :issues => issues,
- :days => days,
- :issues_url => url_for(:controller => 'issues', :action => 'index',
- :set_filter => 1, :assigned_to_id => user.id,
- :sort => 'due_date:asc')
- render_multipart('reminder', body)
- end
-
- # Builds a tmail object used to email users belonging to the added document's project.
- #
- # Example:
- # document_added(document) => tmail object
- # Mailer.deliver_document_added(document) => sends an email to the document's project recipients
- def document_added(document)
- redmine_headers 'Project' => document.project.identifier
- recipients document.recipients
- subject "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
- body :document => document,
- :document_url => url_for(:controller => 'documents', :action => 'show', :id => document)
- render_multipart('document_added', body)
- end
-
- # Builds a tmail object used to email recipients of a project when an attachements are added.
- #
- # Example:
- # attachments_added(attachments) => tmail object
- # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients
- def attachments_added(attachments)
- container = attachments.first.container
- added_to = ''
- added_to_url = ''
- case container.class.name
- when 'Project'
- added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
- added_to = "#{l(:label_project)}: #{container}"
- recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
- when 'Version'
- added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
- added_to = "#{l(:label_version)}: #{container.name}"
- recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
- when 'Document'
- added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
- added_to = "#{l(:label_document)}: #{container.title}"
- recipients container.recipients
- end
- redmine_headers 'Project' => container.project.identifier
- subject "[#{container.project.name}] #{l(:label_attachment_new)}"
- body :attachments => attachments,
- :added_to => added_to,
- :added_to_url => added_to_url
- render_multipart('attachments_added', body)
- end
-
- # Builds a tmail object used to email recipients of a news' project when a news item is added.
- #
- # Example:
- # news_added(news) => tmail object
- # Mailer.deliver_news_added(news) => sends an email to the news' project recipients
- def news_added(news)
- redmine_headers 'Project' => news.project.identifier
- message_id news
- recipients news.recipients
- subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
- body :news => news,
- :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
- render_multipart('news_added', body)
- end
-
- # Builds a tmail object used to email recipients of a news' project when a news comment is added.
- #
- # Example:
- # news_comment_added(comment) => tmail object
- # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
- def news_comment_added(comment)
- news = comment.commented
- redmine_headers 'Project' => news.project.identifier
- message_id comment
- recipients news.recipients
- cc news.watcher_recipients
- subject "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
- body :news => news,
- :comment => comment,
- :news_url => url_for(:controller => 'news', :action => 'show', :id => news)
- render_multipart('news_comment_added', body)
- end
-
- # Builds a tmail object used to email the recipients of the specified message that was posted.
- #
- # Example:
- # message_posted(message) => tmail object
- # Mailer.deliver_message_posted(message) => sends an email to the recipients
- def message_posted(message)
- redmine_headers 'Project' => message.project.identifier,
- 'Topic-Id' => (message.parent_id || message.id)
- message_id message
- references message.parent unless message.parent.nil?
- recipients(message.recipients)
- cc((message.root.watcher_recipients + message.board.watcher_recipients).uniq - @recipients)
- subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
- body :message => message,
- :message_url => url_for(message.event_url)
- render_multipart('message_posted', body)
- end
-
- # Builds a tmail object used to email the recipients of a project of the specified wiki content was added.
- #
- # Example:
- # wiki_content_added(wiki_content) => tmail object
- # Mailer.deliver_wiki_content_added(wiki_content) => sends an email to the project's recipients
- def wiki_content_added(wiki_content)
- redmine_headers 'Project' => wiki_content.project.identifier,
- 'Wiki-Page-Id' => wiki_content.page.id
- message_id wiki_content
- recipients wiki_content.recipients
- cc(wiki_content.page.wiki.watcher_recipients - recipients)
- subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
- body :wiki_content => wiki_content,
- :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
- :project_id => wiki_content.project,
- :id => wiki_content.page.title)
- render_multipart('wiki_content_added', body)
- end
-
- # Builds a tmail object used to email the recipients of a project of the specified wiki content was updated.
- #
- # Example:
- # wiki_content_updated(wiki_content) => tmail object
- # Mailer.deliver_wiki_content_updated(wiki_content) => sends an email to the project's recipients
- def wiki_content_updated(wiki_content)
- redmine_headers 'Project' => wiki_content.project.identifier,
- 'Wiki-Page-Id' => wiki_content.page.id
- message_id wiki_content
- recipients wiki_content.recipients
- cc(wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients)
- subject "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
- body :wiki_content => wiki_content,
- :wiki_content_url => url_for(:controller => 'wiki', :action => 'show',
- :project_id => wiki_content.project,
- :id => wiki_content.page.title),
- :wiki_diff_url => url_for(:controller => 'wiki', :action => 'diff',
- :project_id => wiki_content.project, :id => wiki_content.page.title,
- :version => wiki_content.version)
- render_multipart('wiki_content_updated', body)
- end
-
- # Builds a tmail object used to email the specified user their account information.
- #
- # Example:
- # account_information(user, password) => tmail object
- # Mailer.deliver_account_information(user, password) => sends account information to the user
- def account_information(user, password)
- set_language_if_valid user.language
- recipients user.mail
- subject l(:mail_subject_register, Setting.app_title)
- body :user => user,
- :password => password,
- :login_url => url_for(:controller => 'account', :action => 'login')
- render_multipart('account_information', body)
- end
-
- # Builds a tmail object used to email all active administrators of an account activation request.
- #
- # Example:
- # account_activation_request(user) => tmail object
- # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators
- def account_activation_request(user)
- # Send the email to all active administrators
- recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact
- subject l(:mail_subject_account_activation_request, Setting.app_title)
- body :user => user,
- :url => url_for(:controller => 'users', :action => 'index',
- :status => User::STATUS_REGISTERED,
- :sort_key => 'created_on', :sort_order => 'desc')
- render_multipart('account_activation_request', body)
- end
-
- # Builds a tmail object used to email the specified user that their account was activated by an administrator.
- #
- # Example:
- # account_activated(user) => tmail object
- # Mailer.deliver_account_activated(user) => sends an email to the registered user
- def account_activated(user)
- set_language_if_valid user.language
- recipients user.mail
- subject l(:mail_subject_register, Setting.app_title)
- body :user => user,
- :login_url => url_for(:controller => 'account', :action => 'login')
- render_multipart('account_activated', body)
- end
-
- def lost_password(token)
- set_language_if_valid(token.user.language)
- recipients token.user.mail
- subject l(:mail_subject_lost_password, Setting.app_title)
- body :token => token,
- :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
- render_multipart('lost_password', body)
- end
-
- def register(token)
- set_language_if_valid(token.user.language)
- recipients token.user.mail
- subject l(:mail_subject_register, Setting.app_title)
- body :token => token,
- :url => url_for(:controller => 'account', :action => 'activate', :token => token.value)
- render_multipart('register', body)
- end
-
- def test(user)
- set_language_if_valid(user.language)
- recipients user.mail
- subject 'Redmine test'
- body :url => url_for(:controller => 'welcome')
- render_multipart('test', body)
- end
-
- # Overrides default deliver! method to prevent from sending an email
- # with no recipient, cc or bcc
- def deliver!(mail = @mail)
- set_language_if_valid @initial_language
- return false if (recipients.nil? || recipients.empty?) &&
- (cc.nil? || cc.empty?) &&
- (bcc.nil? || bcc.empty?)
-
- # Set Message-Id and References
- if @message_id_object
- mail.message_id = self.class.message_id_for(@message_id_object)
- end
- if @references_objects
- mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
- end
-
- # Log errors when raise_delivery_errors is set to false, Rails does not
- raise_errors = self.class.raise_delivery_errors
- self.class.raise_delivery_errors = true
- begin
- return super(mail)
- rescue Exception => e
- if raise_errors
- raise e
- elsif mylogger
- mylogger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml."
- end
- ensure
- self.class.raise_delivery_errors = raise_errors
- end
- end
-
- # Sends reminders to issue assignees
- # Available options:
- # * :days => how many days in the future to remind about (defaults to 7)
- # * :tracker => id of tracker for filtering issues (defaults to all trackers)
- # * :project => id or identifier of project to process (defaults to all projects)
- # * :users => array of user ids who should be reminded
- def self.reminders(options={})
- days = options[:days] || 7
- project = options[:project] ? Project.find(options[:project]) : nil
- tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
- user_ids = options[:users]
-
- s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date]
- s << "#{Issue.table_name}.assigned_to_id IS NOT NULL"
- s << ["#{Issue.table_name}.assigned_to_id IN (?)", user_ids] if user_ids.present?
- s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}"
- s << "#{Issue.table_name}.project_id = #{project.id}" if project
- s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker
-
- issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker],
- :conditions => s.conditions
- ).group_by(&:assigned_to)
- issues_by_assignee.each do |assignee, issues|
- deliver_reminder(assignee, issues, days) if assignee && assignee.active?
- end
- end
-
- # Activates/desactivates email deliveries during +block+
- def self.with_deliveries(enabled = true, &block)
- was_enabled = ActionMailer::Base.perform_deliveries
- ActionMailer::Base.perform_deliveries = !!enabled
- yield
- ensure
- ActionMailer::Base.perform_deliveries = was_enabled
- end
-
- private
- def initialize_defaults(method_name)
- super
- @initial_language = current_language
- set_language_if_valid Setting.default_language
- from Setting.mail_from
-
- # Common headers
- headers 'X-Mailer' => 'Redmine',
- 'X-Redmine-Host' => Setting.host_name,
- 'X-Redmine-Site' => Setting.app_title,
- 'X-Auto-Response-Suppress' => 'OOF',
- 'Auto-Submitted' => 'auto-generated'
- end
-
- # Appends a Redmine header field (name is prepended with 'X-Redmine-')
- def redmine_headers(h)
- h.each { |k,v| headers["X-Redmine-#{k}"] = v }
- end
-
- # Overrides the create_mail method
- def create_mail
- # Removes the current user from the recipients and cc
- # if he doesn't want to receive notifications about what he does
- @author ||= User.current
- if @author.pref[:no_self_notified]
- recipients.delete(@author.mail) if recipients
- cc.delete(@author.mail) if cc
- end
-
- notified_users = [recipients, cc].flatten.compact.uniq
- # Rails would log recipients only, not cc and bcc
- mylogger.info "Sending email notification to: #{notified_users.join(', ')}" if mylogger
-
- # Blind carbon copy recipients
- if Setting.bcc_recipients?
- bcc(notified_users)
- recipients []
- cc []
- end
- super
- end
-
- # Rails 2.3 has problems rendering implicit multipart messages with
- # layouts so this method will wrap an multipart messages with
- # explicit parts.
- #
- # https://rails.lighthouseapp.com/projects/8994/tickets/2338-actionmailer-mailer-views-and-content-type
- # https://rails.lighthouseapp.com/projects/8994/tickets/1799-actionmailer-doesnt-set-template_format-when-rendering-layouts
-
- def render_multipart(method_name, body)
- if Setting.plain_text_mail?
- content_type "text/plain"
- body render(:file => "#{method_name}.text.erb",
- :body => body,
- :layout => 'mailer.text.erb')
- else
- content_type "multipart/alternative"
- part :content_type => "text/plain",
- :body => render(:file => "#{method_name}.text.erb",
- :body => body, :layout => 'mailer.text.erb')
- part :content_type => "text/html",
- :body => render_message("#{method_name}.html.erb", body)
- end
- end
-
- # Makes partial rendering work with Rails 1.2 (retro-compatibility)
- def self.controller_path
- ''
- end unless respond_to?('controller_path')
-
- # Returns a predictable Message-Id for the given object
- def self.message_id_for(object)
- # id + timestamp should reduce the odds of a collision
- # as far as we don't send multiple emails for the same object
- 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")}"
- host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
- host = "#{::Socket.gethostname}.redmine" if host.empty?
- "<#{hash}@#{host}>"
- end
-
- private
-
- def message_id(object)
- @message_id_object = object
- end
-
- def references(object)
- @references_objects ||= []
- @references_objects << object
- end
-
- def mylogger
- Rails.logger
- end
-end
-
-# Patch TMail so that message_id is not overwritten
-module TMail
- class Mail
- def add_message_id( fqdn = nil )
- self.message_id ||= ::TMail::new_message_id(fqdn)
- end
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/a6/a698a7c63fb02fea3b0e007c142739ab5d32692d.svn-base
--- a/.svn/pristine/a6/a698a7c63fb02fea3b0e007c142739ab5d32692d.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-class IssueStatus < ActiveRecord::Base
- generator_for :name, :start => 'Status 0'
-
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/a6/a6997ccc17a181acc99da46c561e5d03a8fd1b93.svn-base
--- a/.svn/pristine/a6/a6997ccc17a181acc99da46c561e5d03a8fd1b93.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-class DocumentCategory < Enumeration
- generator_for :name, :start => 'DocumentCategory0'
- generator_for :type => 'DocumentCategory'
-
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/ab/ab0b0facfbc991347f12721c7dda23510d7acb8c.svn-base
--- a/.svn/pristine/ab/ab0b0facfbc991347f12721c7dda23510d7acb8c.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-class CustomField < ActiveRecord::Base
- generator_for :name, :start => 'CustomField0'
- generator_for :field_format => 'string'
-
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/ab/ab1771a93ca21896e5fcd177b31086235de0d81c.svn-base
--- a/.svn/pristine/ab/ab1771a93ca21896e5fcd177b31086235de0d81c.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class NewsController < ApplicationController
- default_search_scope :news
- model_object News
- before_filter :find_model_object, :except => [:new, :create, :index]
- before_filter :find_project_from_association, :except => [:new, :create, :index]
- before_filter :find_project, :only => [:new, :create]
- before_filter :authorize, :except => [:index]
- before_filter :find_optional_project, :only => :index
- accept_rss_auth :index
- accept_api_auth :index
-
- helper :watchers
-
- def index
- case params[:format]
- when 'xml', 'json'
- @offset, @limit = api_offset_and_limit
- else
- @limit = 10
- end
-
- scope = @project ? @project.news.visible : News.visible
-
- @news_count = scope.count
- @news_pages = Paginator.new self, @news_count, @limit, params['page']
- @offset ||= @news_pages.current.offset
- @newss = scope.all(:include => [:author, :project],
- :order => "#{News.table_name}.created_on DESC",
- :offset => @offset,
- :limit => @limit)
-
- respond_to do |format|
- format.html {
- @news = News.new # for adding news inline
- render :layout => false if request.xhr?
- }
- format.api
- format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") }
- end
- end
-
- def show
- @comments = @news.comments
- @comments.reverse! if User.current.wants_comments_in_reverse_order?
- end
-
- def new
- @news = News.new(:project => @project, :author => User.current)
- end
-
- def create
- @news = News.new(:project => @project, :author => User.current)
- if request.post?
- @news.attributes = params[:news]
- if @news.save
- flash[:notice] = l(:notice_successful_create)
- redirect_to :controller => 'news', :action => 'index', :project_id => @project
- else
- render :action => 'new'
- end
- end
- end
-
- def edit
- end
-
- def update
- if request.put? and @news.update_attributes(params[:news])
- flash[:notice] = l(:notice_successful_update)
- redirect_to :action => 'show', :id => @news
- else
- render :action => 'edit'
- end
- end
-
- def destroy
- @news.destroy
- redirect_to :action => 'index', :project_id => @project
- end
-
-private
- def find_project
- @project = Project.find(params[:project_id])
- rescue ActiveRecord::RecordNotFound
- render_404
- end
-
- def find_optional_project
- return true unless params[:project_id]
- @project = Project.find(params[:project_id])
- authorize
- rescue ActiveRecord::RecordNotFound
- render_404
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/ae/aebee85ad90b77d6c4bc7dda8b09ed22d5f72b29.svn-base
--- a/.svn/pristine/ae/aebee85ad90b77d6c4bc7dda8b09ed22d5f72b29.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class WikisController < ApplicationController
- menu_item :settings
- before_filter :find_project, :authorize
-
- # Create or update a project's wiki
- def edit
- @wiki = @project.wiki || Wiki.new(:project => @project)
- @wiki.attributes = params[:wiki]
- @wiki.save if request.post?
- render(:update) {|page| page.replace_html "tab-content-wiki", :partial => 'projects/settings/wiki'}
- end
-
- # Delete a project's wiki
- def destroy
- if request.post? && params[:confirm] && @project.wiki
- @project.wiki.destroy
- redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'wiki'
- end
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/b2/b28ce953654e531c6ddefb215755b888c0d45031.svn-base
--- a/.svn/pristine/b2/b28ce953654e531c6ddefb215755b888c0d45031.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require File.expand_path('../../test_helper', __FILE__)
-
-class NewsTest < ActiveSupport::TestCase
- fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :news
-
- def valid_news
- { :title => 'Test news', :description => 'Lorem ipsum etc', :author => User.find(:first) }
- end
-
- def setup
- end
-
- def test_create_should_send_email_notification
- ActionMailer::Base.deliveries.clear
- Setting.notified_events << 'news_added'
- news = Project.find(:first).news.new(valid_news)
-
- assert news.save
- assert_equal 1, ActionMailer::Base.deliveries.size
- end
-
- def test_should_include_news_for_projects_with_news_enabled
- project = projects(:projects_001)
- assert project.enabled_modules.any?{ |em| em.name == 'news' }
-
- # News.latest should return news from projects_001
- assert News.latest.any? { |news| news.project == project }
- end
-
- def test_should_not_include_news_for_projects_with_news_disabled
- EnabledModule.delete_all(["project_id = ? AND name = ?", 2, 'news'])
- project = Project.find(2)
-
- # Add a piece of news to the project
- news = project.news.create(valid_news)
-
- # News.latest should not return that new piece of news
- assert News.latest.include?(news) == false
- end
-
- def test_should_only_include_news_from_projects_visibly_to_the_user
- assert News.latest(User.anonymous).all? { |news| news.project.is_public? }
- end
-
- def test_should_limit_the_amount_of_returned_news
- # Make sure we have a bunch of news stories
- 10.times { projects(:projects_001).news.create(valid_news) }
- assert_equal 2, News.latest(users(:users_002), 2).size
- assert_equal 6, News.latest(users(:users_002), 6).size
- end
-
- def test_should_return_5_news_stories_by_default
- # Make sure we have a bunch of news stories
- 10.times { projects(:projects_001).news.create(valid_news) }
- assert_equal 5, News.latest(users(:users_004)).size
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/b7/b78206ca607096e92e37aa8306eed7eb741f79b9.svn-base
--- a/.svn/pristine/b7/b78206ca607096e92e37aa8306eed7eb741f79b9.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +0,0 @@
-# encoding: utf-8
-#
-# Helpers to sort tables using clickable column headers.
-#
-# Author: Stuart Rackham , March 2005.
-# Jean-Philippe Lang, 2009
-# License: This source code is released under the MIT license.
-#
-# - Consecutive clicks toggle the column's sort order.
-# - Sort state is maintained by a session hash entry.
-# - CSS classes identify sort column and state.
-# - Typically used in conjunction with the Pagination module.
-#
-# Example code snippets:
-#
-# Controller:
-#
-# helper :sort
-# include SortHelper
-#
-# def list
-# sort_init 'last_name'
-# sort_update %w(first_name last_name)
-# @items = Contact.find_all nil, sort_clause
-# end
-#
-# Controller (using Pagination module):
-#
-# helper :sort
-# include SortHelper
-#
-# def list
-# sort_init 'last_name'
-# sort_update %w(first_name last_name)
-# @contact_pages, @items = paginate :contacts,
-# :order_by => sort_clause,
-# :per_page => 10
-# end
-#
-# View (table header in list.rhtml):
-#
-#
-#
-# <%= sort_header_tag('id', :title => 'Sort by contact ID') %>
-# <%= sort_header_tag('last_name', :caption => 'Name') %>
-# <%= sort_header_tag('phone') %>
-# <%= sort_header_tag('address', :width => 200) %>
-#
-#
-#
-# - Introduces instance variables: @sort_default, @sort_criteria
-# - Introduces param :sort
-#
-
-module SortHelper
- class SortCriteria
-
- def initialize
- @criteria = []
- end
-
- def available_criteria=(criteria)
- unless criteria.is_a?(Hash)
- criteria = criteria.inject({}) {|h,k| h[k] = k; h}
- end
- @available_criteria = criteria
- end
-
- def from_param(param)
- @criteria = param.to_s.split(',').collect {|s| s.split(':')[0..1]}
- normalize!
- end
-
- def criteria=(arg)
- @criteria = arg
- normalize!
- end
-
- def to_param
- @criteria.collect {|k,o| k + (o ? '' : ':desc')}.join(',')
- end
-
- def to_sql
- sql = @criteria.collect do |k,o|
- if s = @available_criteria[k]
- (o ? s.to_a : s.to_a.collect {|c| append_desc(c)}).join(', ')
- end
- end.compact.join(', ')
- sql.blank? ? nil : sql
- end
-
- def add!(key, asc)
- @criteria.delete_if {|k,o| k == key}
- @criteria = [[key, asc]] + @criteria
- normalize!
- end
-
- def add(*args)
- r = self.class.new.from_param(to_param)
- r.add!(*args)
- r
- end
-
- def first_key
- @criteria.first && @criteria.first.first
- end
-
- def first_asc?
- @criteria.first && @criteria.first.last
- end
-
- def empty?
- @criteria.empty?
- end
-
- private
-
- def normalize!
- @criteria ||= []
- @criteria = @criteria.collect {|s| s = s.to_a; [s.first, (s.last == false || s.last == 'desc') ? false : true]}
- @criteria = @criteria.select {|k,o| @available_criteria.has_key?(k)} if @available_criteria
- @criteria.slice!(3)
- self
- end
-
- # Appends DESC to the sort criterion unless it has a fixed order
- def append_desc(criterion)
- if criterion =~ / (asc|desc)$/i
- criterion
- else
- "#{criterion} DESC"
- end
- end
- end
-
- def sort_name
- controller_name + '_' + action_name + '_sort'
- end
-
- # Initializes the default sort.
- # Examples:
- #
- # sort_init 'name'
- # sort_init 'id', 'desc'
- # sort_init ['name', ['id', 'desc']]
- # sort_init [['name', 'desc'], ['id', 'desc']]
- #
- def sort_init(*args)
- case args.size
- when 1
- @sort_default = args.first.is_a?(Array) ? args.first : [[args.first]]
- when 2
- @sort_default = [[args.first, args.last]]
- else
- raise ArgumentError
- end
- end
-
- # Updates the sort state. Call this in the controller prior to calling
- # sort_clause.
- # - criteria can be either an array or a hash of allowed keys
- #
- def sort_update(criteria)
- @sort_criteria = SortCriteria.new
- @sort_criteria.available_criteria = criteria
- @sort_criteria.from_param(params[:sort] || session[sort_name])
- @sort_criteria.criteria = @sort_default if @sort_criteria.empty?
- session[sort_name] = @sort_criteria.to_param
- end
-
- # Clears the sort criteria session data
- #
- def sort_clear
- session[sort_name] = nil
- end
-
- # Returns an SQL sort clause corresponding to the current sort state.
- # Use this to sort the controller's table items collection.
- #
- def sort_clause()
- @sort_criteria.to_sql
- end
-
- # Returns a link which sorts by the named column.
- #
- # - column is the name of an attribute in the sorted record collection.
- # - the optional caption explicitly specifies the displayed link text.
- # - 2 CSS classes reflect the state of the link: sort and asc or desc
- #
- def sort_link(column, caption, default_order)
- css, order = nil, default_order
-
- if column.to_s == @sort_criteria.first_key
- if @sort_criteria.first_asc?
- css = 'sort asc'
- order = 'desc'
- else
- css = 'sort desc'
- order = 'asc'
- end
- end
- caption = column.to_s.humanize unless caption
-
- sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param }
- url_options = params.merge(sort_options)
-
- # Add project_id to url_options
- url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id)
-
- link_to_content_update(h(caption), url_options, :class => css)
- end
-
- # Returns a table header tag with a sort link for the named column
- # attribute.
- #
- # Options:
- # :caption The displayed link name (defaults to titleized column name).
- # :title The tag's 'title' attribute (defaults to 'Sort by :caption').
- #
- # Other options hash entries generate additional table header tag attributes.
- #
- # Example:
- #
- # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %>
- #
- def sort_header_tag(column, options = {})
- caption = options.delete(:caption) || column.to_s.humanize
- default_order = options.delete(:default_order) || 'asc'
- options[:title] = l(:label_sort_by, "\"#{caption}\"") unless options[:title]
- content_tag('th', sort_link(column, caption, default_order), options)
- end
-end
-
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/b8/b82223fbdec52f206edc9d2ad2ddfa5e3b1780f5.svn-base
--- a/.svn/pristine/b8/b82223fbdec52f206edc9d2ad2ddfa5e3b1780f5.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-module WatchersHelper
-
- def watcher_tag(object, user, options={})
- content_tag("span", watcher_link(object, user), :class => watcher_css(object))
- end
-
- def watcher_link(object, user)
- return '' unless user && user.logged? && object.respond_to?('watched_by?')
- watched = object.watched_by?(user)
- url = {:controller => 'watchers',
- :action => (watched ? 'unwatch' : 'watch'),
- :object_type => object.class.to_s.underscore,
- :object_id => object.id}
- link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)),
- {:url => url},
- :href => url_for(url),
- :class => (watched ? 'icon icon-fav' : 'icon icon-fav-off'))
-
- end
-
- # Returns the css class used to identify watch links for a given +object+
- def watcher_css(object)
- "#{object.class.to_s.underscore}-#{object.id}-watcher"
- end
-
- # Returns a comma separated list of users watching the given object
- def watchers_list(object)
- remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project)
- lis = object.watcher_users.collect do |user|
- s = avatar(user, :size => "16").to_s + link_to_user(user, :class => 'user').to_s
- if remove_allowed
- url = {:controller => 'watchers',
- :action => 'destroy',
- :object_type => object.class.to_s.underscore,
- :object_id => object.id,
- :user_id => user}
- s += ' ' + link_to_remote(image_tag('delete.png'),
- {:url => url},
- :href => url_for(url),
- :style => "vertical-align: middle",
- :class => "delete")
- end
- "#{ s } "
- end
- lis.empty? ? "" : ""
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/b9/b96e921475f2f40185ea321c703c1a004b648084.svn-base
--- a/.svn/pristine/b9/b96e921475f2f40185ea321c703c1a004b648084.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-class News < ActiveRecord::Base
- generator_for :title, :start => 'A New Item'
- generator_for :description, :start => 'Some content here'
-
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/b9/b9f89fb226038b5fa935152e7e423f28e9c772a3.svn-base
--- a/.svn/pristine/b9/b9f89fb226038b5fa935152e7e423f28e9c772a3.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-# encoding: utf-8
-#
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-module CustomFieldsHelper
-
- def custom_fields_tabs
- tabs = [{:name => 'IssueCustomField', :partial => 'custom_fields/index', :label => :label_issue_plural},
- {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', :label => :label_spent_time},
- {:name => 'ProjectCustomField', :partial => 'custom_fields/index', :label => :label_project_plural},
- {:name => 'VersionCustomField', :partial => 'custom_fields/index', :label => :label_version_plural},
- {:name => 'UserCustomField', :partial => 'custom_fields/index', :label => :label_user_plural},
- {:name => 'GroupCustomField', :partial => 'custom_fields/index', :label => :label_group_plural},
- {:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index', :label => TimeEntryActivity::OptionName},
- {:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index', :label => IssuePriority::OptionName},
- {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index', :label => DocumentCategory::OptionName}
- ]
- end
-
- # Return custom field html tag corresponding to its format
- def custom_field_tag(name, custom_value)
- custom_field = custom_value.custom_field
- field_name = "#{name}[custom_field_values][#{custom_field.id}]"
- field_id = "#{name}_custom_field_values_#{custom_field.id}"
-
- field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
- case field_format.try(:edit_as)
- when "date"
- text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) +
- calendar_for(field_id)
- when "text"
- text_area_tag(field_name, custom_value.value, :id => field_id, :rows => 3, :style => 'width:90%')
- when "bool"
- hidden_field_tag(field_name, '0') + check_box_tag(field_name, '1', custom_value.true?, :id => field_id)
- when "list"
- blank_option = custom_field.is_required? ?
- (custom_field.default_value.blank? ? "--- #{l(:actionview_instancetag_blank_option)} --- " : '') :
- ' '
- select_tag(field_name, blank_option + options_for_select(custom_field.possible_values_options(custom_value.customized), custom_value.value), :id => field_id)
- else
- text_field_tag(field_name, custom_value.value, :id => field_id)
- end
- end
-
- # Return custom field label tag
- def custom_field_label_tag(name, custom_value)
- content_tag "label", h(custom_value.custom_field.name) +
- (custom_value.custom_field.is_required? ? " * ".html_safe : ""),
- :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}",
- :class => (custom_value.errors.empty? ? nil : "error" )
- end
-
- # Return custom field tag with its label tag
- def custom_field_tag_with_label(name, custom_value)
- custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value)
- end
-
- def custom_field_tag_for_bulk_edit(name, custom_field, projects=nil)
- field_name = "#{name}[custom_field_values][#{custom_field.id}]"
- field_id = "#{name}_custom_field_values_#{custom_field.id}"
- field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
- case field_format.try(:edit_as)
- when "date"
- text_field_tag(field_name, '', :id => field_id, :size => 10) +
- calendar_for(field_id)
- when "text"
- text_area_tag(field_name, '', :id => field_id, :rows => 3, :style => 'width:90%')
- when "bool"
- select_tag(field_name, options_for_select([[l(:label_no_change_option), ''],
- [l(:general_text_yes), '1'],
- [l(:general_text_no), '0']]), :id => field_id)
- when "list"
- select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values_options(projects)), :id => field_id)
- else
- text_field_tag(field_name, '', :id => field_id)
- end
- end
-
- # Return a string used to display a custom value
- def show_value(custom_value)
- return "" unless custom_value
- format_value(custom_value.value, custom_value.custom_field.field_format)
- end
-
- # Return a string used to display a custom value
- def format_value(value, field_format)
- Redmine::CustomFieldFormat.format_value(value, field_format) # Proxy
- end
-
- # Return an array of custom field formats which can be used in select_tag
- def custom_field_formats_for_select(custom_field)
- Redmine::CustomFieldFormat.as_select(custom_field.class.customized_class.name)
- end
-
- # Renders the custom_values in api views
- def render_api_custom_values(custom_values, api)
- api.array :custom_fields do
- custom_values.each do |custom_value|
- api.custom_field :id => custom_value.custom_field_id, :name => custom_value.custom_field.name do
- api.value custom_value.value
- end
- end
- end unless custom_values.empty?
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/ba/ba14e0cc7fc34e88acaa1138bf2dde298dda1f32.svn-base
--- a/.svn/pristine/ba/ba14e0cc7fc34e88acaa1138bf2dde298dda1f32.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-class TimeEntry < ActiveRecord::Base
- # could have used polymorphic association
- # project association here allows easy loading of time entries at project level with one database trip
- belongs_to :project
- belongs_to :issue
- belongs_to :user
- belongs_to :activity, :class_name => 'TimeEntryActivity', :foreign_key => 'activity_id'
-
- attr_protected :project_id, :user_id, :tyear, :tmonth, :tweek
-
- acts_as_customizable
- acts_as_event :title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"},
- :url => Proc.new {|o| {:controller => 'timelog', :action => 'index', :project_id => o.project, :issue_id => o.issue}},
- :author => :user,
- :description => :comments
-
- acts_as_activity_provider :timestamp => "#{table_name}.created_on",
- :author_key => :user_id,
- :find_options => {:include => :project}
-
- validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
- validates_numericality_of :hours, :allow_nil => true, :message => :invalid
- validates_length_of :comments, :maximum => 255, :allow_nil => true
- before_validation :set_project_if_nil
- validate :validate_time_entry
-
- named_scope :visible, lambda {|*args| {
- :include => :project,
- :conditions => Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args)
- }}
-
- def after_initialize
- if new_record? && self.activity.nil?
- if default_activity = TimeEntryActivity.default
- self.activity_id = default_activity.id
- end
- self.hours = nil if hours == 0
- end
- end
-
- def set_project_if_nil
- self.project = issue.project if issue && project.nil?
- end
-
- def validate_time_entry
- errors.add :hours, :invalid if hours && (hours < 0 || hours >= 1000)
- errors.add :project_id, :invalid if project.nil?
- errors.add :issue_id, :invalid if (issue_id && !issue) || (issue && project!=issue.project)
- end
-
- def hours=(h)
- write_attribute :hours, (h.is_a?(String) ? (h.to_hours || h) : h)
- end
-
- # tyear, tmonth, tweek assigned where setting spent_on attributes
- # these attributes make time aggregations easier
- def spent_on=(date)
- super
- if spent_on.is_a?(Time)
- self.spent_on = spent_on.to_date
- end
- self.tyear = spent_on ? spent_on.year : nil
- self.tmonth = spent_on ? spent_on.month : nil
- self.tweek = spent_on ? Date.civil(spent_on.year, spent_on.month, spent_on.day).cweek : nil
- end
-
- # Returns true if the time entry can be edited by usr, otherwise false
- def editable_by?(usr)
- (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project)
- end
-
- def self.earilest_date_for_project(project=nil)
- finder_conditions = ARCondition.new(Project.allowed_to_condition(User.current, :view_time_entries))
- if project
- finder_conditions << ["project_id IN (?)", project.hierarchy.collect(&:id)]
- end
- TimeEntry.minimum(:spent_on, :include => :project, :conditions => finder_conditions.conditions)
- end
-
- def self.latest_date_for_project(project=nil)
- finder_conditions = ARCondition.new(Project.allowed_to_condition(User.current, :view_time_entries))
- if project
- finder_conditions << ["project_id IN (?)", project.hierarchy.collect(&:id)]
- end
- TimeEntry.maximum(:spent_on, :include => :project, :conditions => finder_conditions.conditions)
- end
-end
diff -r 5f33065ddc4b -r 433d4f72a19b .svn/pristine/bb/bb26d7134db2daa8e385e20efdf915f60c0f95a4.svn-base
--- a/.svn/pristine/bb/bb26d7134db2daa8e385e20efdf915f60c0f95a4.svn-base Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,878 +0,0 @@
-# Redmine - project management software
-# Copyright (C) 2006-2011 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require File.expand_path('../../../test_helper', __FILE__)
-
-class ApplicationHelperTest < ActionView::TestCase
- fixtures :projects, :roles, :enabled_modules, :users,
- :repositories, :changesets,
- :trackers, :issue_statuses, :issues, :versions, :documents,
- :wikis, :wiki_pages, :wiki_contents,
- :boards, :messages, :news,
- :attachments, :enumerations
-
- def setup
- super
- set_tmp_attachments_directory
- end
-
- context "#link_to_if_authorized" do
- context "authorized user" do
- should "be tested"
- end
-
- context "unauthorized user" do
- should "be tested"
- end
-
- should "allow using the :controller and :action for the target link" do
- User.current = User.find_by_login('admin')
-
- @project = Issue.first.project # Used by helper
- response = link_to_if_authorized("By controller/action",
- {:controller => 'issues', :action => 'edit', :id => Issue.first.id})
- assert_match /href/, response
- end
-
- end
-
- def test_auto_links
- to_test = {
- 'http://foo.bar' => 'http://foo.bar ',
- 'http://foo.bar/~user' => 'http://foo.bar/~user ',
- 'http://foo.bar.' => 'http://foo.bar .',
- 'https://foo.bar.' => 'https://foo.bar .',
- 'This is a link: http://foo.bar.' => 'This is a link: http://foo.bar .',
- 'A link (eg. http://foo.bar).' => 'A link (eg. http://foo.bar ).',
- 'http://foo.bar/foo.bar#foo.bar.' => 'http://foo.bar/foo.bar#foo.bar .',
- 'http://www.foo.bar/Test_(foobar)' => 'http://www.foo.bar/Test_(foobar) ',
- '(see inline link : http://www.foo.bar/Test_(foobar))' => '(see inline link : http://www.foo.bar/Test_(foobar) )',
- '(see inline link : http://www.foo.bar/Test)' => '(see inline link : http://www.foo.bar/Test )',
- '(see inline link : http://www.foo.bar/Test).' => '(see inline link : http://www.foo.bar/Test ).',
- '(see "inline link":http://www.foo.bar/Test_(foobar))' => '(see inline link )',
- '(see "inline link":http://www.foo.bar/Test)' => '(see inline link )',
- '(see "inline link":http://www.foo.bar/Test).' => '(see inline link ).',
- 'www.foo.bar' => 'www.foo.bar ',
- 'http://foo.bar/page?p=1&t=z&s=' => 'http://foo.bar/page?p=1&t=z&s= ',
- 'http://foo.bar/page#125' => 'http://foo.bar/page#125 ',
- 'http://foo@www.bar.com' => 'http://foo@www.bar.com ',
- 'http://foo:bar@www.bar.com' => 'http://foo:bar@www.bar.com ',
- 'ftp://foo.bar' => 'ftp://foo.bar ',
- 'ftps://foo.bar' => 'ftps://foo.bar ',
- 'sftp://foo.bar' => 'sftp://foo.bar ',
- # two exclamation marks
- 'http://example.net/path!602815048C7B5C20!302.html' => 'http://example.net/path!602815048C7B5C20!302.html ',
- # escaping
- 'http://foo"bar' => 'http://foo"bar ',
- # wrap in angle brackets
- '' => '<http://foo.bar >'
- }
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text) }
- end
-
- def test_auto_mailto
- assert_equal 'test@foo.bar
',
- textilizable('test@foo.bar')
- end
-
- def test_inline_images
- to_test = {
- '!http://foo.bar/image.jpg!' => ' ',
- 'floating !>http://foo.bar/image.jpg!' => 'floating ',
- 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class ',
- # inline styles should be stripped
- 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style ',
- 'with title !http://foo.bar/image.jpg(This is a title)!' => 'with title ',
- 'with title !http://foo.bar/image.jpg(This is a double-quoted "title")!' => 'with title ',
- }
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text) }
- end
-
- def test_inline_images_inside_tags
- raw = <<-RAW
-h1. !foo.png! Heading
-
-Centered image:
-
-p=. !bar.gif!
-RAW
-
- assert textilizable(raw).include?(' ')
- assert textilizable(raw).include?(' ')
- end
-
- def test_attached_images
- to_test = {
- 'Inline image: !logo.gif!' => 'Inline image: ',
- 'Inline image: !logo.GIF!' => 'Inline image: ',
- 'No match: !ogo.gif!' => 'No match: ',
- 'No match: !ogo.GIF!' => 'No match: ',
- # link image
- '!logo.gif!:http://foo.bar/' => ' ',
- }
- attachments = Attachment.find(:all)
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text, :attachments => attachments) }
- end
-
- def test_attached_images_filename_extension
- set_tmp_attachments_directory
- a1 = Attachment.new(
- :container => Issue.find(1),
- :file => mock_file_with_options({:original_filename => "testtest.JPG"}),
- :author => User.find(1))
- assert a1.save
- assert_equal "testtest.JPG", a1.filename
- assert_equal "image/jpeg", a1.content_type
- assert a1.image?
-
- a2 = Attachment.new(
- :container => Issue.find(1),
- :file => mock_file_with_options({:original_filename => "testtest.jpeg"}),
- :author => User.find(1))
- assert a2.save
- assert_equal "testtest.jpeg", a2.filename
- assert_equal "image/jpeg", a2.content_type
- assert a2.image?
-
- a3 = Attachment.new(
- :container => Issue.find(1),
- :file => mock_file_with_options({:original_filename => "testtest.JPE"}),
- :author => User.find(1))
- assert a3.save
- assert_equal "testtest.JPE", a3.filename
- assert_equal "image/jpeg", a3.content_type
- assert a3.image?
-
- a4 = Attachment.new(
- :container => Issue.find(1),
- :file => mock_file_with_options({:original_filename => "Testtest.BMP"}),
- :author => User.find(1))
- assert a4.save
- assert_equal "Testtest.BMP", a4.filename
- assert_equal "image/x-ms-bmp", a4.content_type
- assert a4.image?
-
- to_test = {
- 'Inline image: !testtest.jpg!' =>
- 'Inline image: ',
- 'Inline image: !testtest.jpeg!' =>
- 'Inline image: ',
- 'Inline image: !testtest.jpe!' =>
- 'Inline image: ',
- 'Inline image: !testtest.bmp!' =>
- 'Inline image: ',
- }
-
- attachments = [a1, a2, a3, a4]
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text, :attachments => attachments) }
- end
-
- def test_attached_images_should_read_later
- Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
- a1 = Attachment.find(16)
- assert_equal "testfile.png", a1.filename
- assert a1.readable?
- assert (! a1.visible?(User.anonymous))
- assert a1.visible?(User.find(2))
- a2 = Attachment.find(17)
- assert_equal "testfile.PNG", a2.filename
- assert a2.readable?
- assert (! a2.visible?(User.anonymous))
- assert a2.visible?(User.find(2))
- assert a1.created_on < a2.created_on
-
- to_test = {
- 'Inline image: !testfile.png!' =>
- 'Inline image: ',
- 'Inline image: !Testfile.PNG!' =>
- 'Inline image: ',
- }
- attachments = [a1, a2]
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text, :attachments => attachments) }
- set_tmp_attachments_directory
- end
-
- def test_textile_external_links
- to_test = {
- 'This is a "link":http://foo.bar' => 'This is a link ',
- 'This is an intern "link":/foo/bar' => 'This is an intern link ',
- '"link (Link title)":http://foo.bar' => 'link ',
- '"link (Link title with "double-quotes")":http://foo.bar' => 'link ',
- "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":\n\n\n\tAnother paragraph",
- # no multiline link text
- "This is a double quote \"on the first line\nand another on a second line\":test" => "This is a double quote \"on the first line and another on a second line\":test",
- # mailto link
- "\"system administrator\":mailto:sysadmin@example.com?subject=redmine%20permissions" => "system administrator ",
- # two exclamation marks
- '"a link":http://example.net/path!602815048C7B5C20!302.html' => 'a link ',
- # escaping
- '"test":http://foo"bar' => 'test ',
- }
- to_test.each { |text, result| assert_equal "
#{result}
", textilizable(text) }
- end
-
- def test_redmine_links
- issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
- :class => 'issue status-1 priority-1 overdue', :title => 'Error 281 when updating a recipe (New)')
-
- changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
- :class => 'changeset', :title => 'My very first commit')
- changeset_link2 = link_to('r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
- :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
-
- document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
- :class => 'document')
-
- version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
- :class => 'version')
-
- board_url = {:controller => 'boards', :action => 'show', :id => 2, :project_id => 'ecookbook'}
-
- message_url = {:controller => 'messages', :action => 'show', :board_id => 1, :id => 4}
-
- news_url = {:controller => 'news', :action => 'show', :id => 1}
-
- project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'}
-
- source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}
- source_url_with_ext = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file.ext']}
-
- to_test = {
- # tickets
- '#3, [#3], (#3) and #3.' => "#{issue_link}, [#{issue_link}], (#{issue_link}) and #{issue_link}.",
- # changesets
- 'r1' => changeset_link,
- 'r1.' => "#{changeset_link}.",
- 'r1, r2' => "#{changeset_link}, #{changeset_link2}",
- 'r1,r2' => "#{changeset_link},#{changeset_link2}",
- # documents
- 'document#1' => document_link,
- 'document:"Test document"' => document_link,
- # versions
- 'version#2' => version_link,
- 'version:1.0' => version_link,
- 'version:"1.0"' => version_link,
- # source
- 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
- 'source:/some/file.' => link_to('source:/some/file', source_url, :class => 'source') + ".",
- 'source:/some/file.ext.' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
- 'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".",
- 'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
- 'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",",
- 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
- 'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_ext.merge(:rev => 52), :class => 'source'),
- 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
- 'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext.merge(:anchor => 'L110'), :class => 'source'),
- 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
- 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
- # forum
- 'forum#2' => link_to('Discussion', board_url, :class => 'board'),
- 'forum:Discussion' => link_to('Discussion', board_url, :class => 'board'),
- # message
- 'message#4' => link_to('Post 2', message_url, :class => 'message'),
- 'message#5' => link_to('RE: post 2', message_url.merge(:anchor => 'message-5', :r => 5), :class => 'message'),
- # news
- 'news#1' => link_to('eCookbook first release !', news_url, :class => 'news'),
- 'news:"eCookbook first release !"' => link_to('eCookbook first release !', news_url, :class => 'news'),
- # project
- 'project#3' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
- 'project:subproject1' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
- 'project:"eCookbook subProject 1"' => link_to('eCookbook Subproject 1', project_url, :class => 'project'),
- # escaping
- '!#3.' => '#3.',
- '!r1' => 'r1',
- '!document#1' => 'document#1',
- '!document:"Test document"' => 'document:"Test document"',
- '!version#2' => 'version#2',
- '!version:1.0' => 'version:1.0',
- '!version:"1.0"' => 'version:"1.0"',
- '!source:/some/file' => 'source:/some/file',
- # not found
- '#0123456789' => '#0123456789',
- # invalid expressions
- 'source:' => 'source:',
- # url hash
- "http://foo.bar/FAQ#3" => 'http://foo.bar/FAQ#3 ',
- }
- @project = Project.find(1)
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text), "#{text} failed" }
- end
-
- def test_cross_project_redmine_links
- source_link = link_to('ecookbook:source:/some/file', {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']},
- :class => 'source')
-
- changeset_link = link_to('ecookbook:r2', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 2},
- :class => 'changeset', :title => 'This commit fixes #1, #2 and references #1 & #3')
-
- to_test = {
- # documents
- 'document:"Test document"' => 'document:"Test document"',
- 'ecookbook:document:"Test document"' => 'Test document ',
- 'invalid:document:"Test document"' => 'invalid:document:"Test document"',
- # versions
- 'version:"1.0"' => 'version:"1.0"',
- 'ecookbook:version:"1.0"' => '1.0 ',
- 'invalid:version:"1.0"' => 'invalid:version:"1.0"',
- # changeset
- 'r2' => 'r2',
- 'ecookbook:r2' => changeset_link,
- 'invalid:r2' => 'invalid:r2',
- # source
- 'source:/some/file' => 'source:/some/file',
- 'ecookbook:source:/some/file' => source_link,
- 'invalid:source:/some/file' => 'invalid:source:/some/file',
- }
- @project = Project.find(3)
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text), "#{text} failed" }
- end
-
- def test_redmine_links_git_commit
- changeset_link = link_to('abcd',
- {
- :controller => 'repositories',
- :action => 'revision',
- :id => 'subproject1',
- :rev => 'abcd',
- },
- :class => 'changeset', :title => 'test commit')
- to_test = {
- 'commit:abcd' => changeset_link,
- }
- @project = Project.find(3)
- r = Repository::Git.create!(:project => @project, :url => '/tmp/test/git')
- assert r
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :revision => 'abcd',
- :scmid => 'abcd',
- :comments => 'test commit')
- assert( c.save )
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text) }
- end
-
- # TODO: Bazaar commit id contains mail address, so it contains '@' and '_'.
- def test_redmine_links_darcs_commit
- changeset_link = link_to('20080308225258-98289-abcd456efg.gz',
- {
- :controller => 'repositories',
- :action => 'revision',
- :id => 'subproject1',
- :rev => '123',
- },
- :class => 'changeset', :title => 'test commit')
- to_test = {
- 'commit:20080308225258-98289-abcd456efg.gz' => changeset_link,
- }
- @project = Project.find(3)
- r = Repository::Darcs.create!(
- :project => @project, :url => '/tmp/test/darcs',
- :log_encoding => 'UTF-8')
- assert r
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :revision => '123',
- :scmid => '20080308225258-98289-abcd456efg.gz',
- :comments => 'test commit')
- assert( c.save )
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text) }
- end
-
- def test_redmine_links_mercurial_commit
- changeset_link_rev = link_to('r123',
- {
- :controller => 'repositories',
- :action => 'revision',
- :id => 'subproject1',
- :rev => '123' ,
- },
- :class => 'changeset', :title => 'test commit')
- changeset_link_commit = link_to('abcd',
- {
- :controller => 'repositories',
- :action => 'revision',
- :id => 'subproject1',
- :rev => 'abcd' ,
- },
- :class => 'changeset', :title => 'test commit')
- to_test = {
- 'r123' => changeset_link_rev,
- 'commit:abcd' => changeset_link_commit,
- }
- @project = Project.find(3)
- r = Repository::Mercurial.create!(:project => @project, :url => '/tmp/test')
- assert r
- c = Changeset.new(:repository => r,
- :committed_on => Time.now,
- :revision => '123',
- :scmid => 'abcd',
- :comments => 'test commit')
- assert( c.save )
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text) }
- end
-
- def test_attachment_links
- attachment_link = link_to('error281.txt', {:controller => 'attachments', :action => 'download', :id => '1'}, :class => 'attachment')
- to_test = {
- 'attachment:error281.txt' => attachment_link
- }
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text, :attachments => Issue.find(3).attachments), "#{text} failed" }
- end
-
- def test_wiki_links
- to_test = {
- '[[CookBook documentation]]' => 'CookBook documentation ',
- '[[Another page|Page]]' => 'Page ',
- # title content should be formatted
- '[[Another page|With _styled_ *title*]]' => 'With styled title ',
- '[[Another page|With title containing HTML entities & markups ]]' => 'With title containing <strong>HTML entities & markups</strong> ',
- # link with anchor
- '[[CookBook documentation#One-section]]' => 'CookBook documentation ',
- '[[Another page#anchor|Page]]' => 'Page ',
- # page that doesn't exist
- '[[Unknown page]]' => 'Unknown page ',
- '[[Unknown page|404]]' => '404 ',
- # link to another project wiki
- '[[onlinestore:]]' => 'onlinestore ',
- '[[onlinestore:|Wiki]]' => 'Wiki ',
- '[[onlinestore:Start page]]' => 'Start page ',
- '[[onlinestore:Start page|Text]]' => 'Text ',
- '[[onlinestore:Unknown page]]' => 'Unknown page ',
- # striked through link
- '-[[Another page|Page]]-' => 'Page ',
- '-[[Another page|Page]] link-' => 'Page link',
- # escaping
- '![[Another page|Page]]' => '[[Another page|Page]]',
- # project does not exist
- '[[unknowproject:Start]]' => '[[unknowproject:Start]]',
- '[[unknowproject:Start|Page title]]' => '[[unknowproject:Start|Page title]]',
- }
-
- @project = Project.find(1)
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text) }
- end
-
- def test_wiki_links_within_local_file_generation_context
-
- to_test = {
- # link to a page
- '[[CookBook documentation]]' => 'CookBook documentation ',
- '[[CookBook documentation|documentation]]' => 'documentation ',
- '[[CookBook documentation#One-section]]' => 'CookBook documentation ',
- '[[CookBook documentation#One-section|documentation]]' => 'documentation ',
- # page that doesn't exist
- '[[Unknown page]]' => 'Unknown page ',
- '[[Unknown page|404]]' => '404 ',
- '[[Unknown page#anchor]]' => 'Unknown page ',
- '[[Unknown page#anchor|404]]' => '404 ',
- }
-
- @project = Project.find(1)
-
- to_test.each { |text, result| assert_equal "#{result}
", textilizable(text, :wiki_links => :local) }
- end
-
- def test_html_tags
- to_test = {
- "content
" => "<div>content</div>
",
- "content
" => "<div class=\"bold\">content</div>
",
- "" => "<script>some script;</script>
",
- # do not escape pre/code tags
- "\nline 1\nline2 " => "\nline 1\nline2 ",
- "\nline 1\nline2
" => "\nline 1\nline2
",
- "content
" => "<div>content</div> ",
- "HTML comment: " => "HTML comment: <!-- no comments -->
",
- "
+
<% if @user.auth_source_id.nil? %>
-
<%=l(:field_login)%> *
-<%= text_field 'user', 'login', :size => 25 %>
+
<%= f.text_field :login, :size => 25, :required => true %>
-
<%=l(:field_password)%> *
-<%= password_field_tag 'password', nil, :size => 25 %>
-<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>
+
<%= f.password_field :password, :size => 25, :required => true %>
+ <%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>
-
<%=l(:field_password_confirmation)%> *
-<%= password_field_tag 'password_confirmation', nil, :size => 25 %>
+
<%= f.password_field :password_confirmation, :size => 25, :required => true %>
<% end %>
-
<%=l(:field_firstname)%> *
-<%= text_field 'user', 'firstname' %>
-
-
<%=l(:field_lastname)%> *
-<%= text_field 'user', 'lastname' %>
-
-
<%=l(:field_mail)%> *
-<%= text_field 'user', 'mail' %>
-
-
<%=l(:field_language)%>
-<%= select("user", "language", lang_options_for_select) %>
+
<%= f.text_field :firstname, :required => true %>
+
<%= f.text_field :lastname, :required => true %>
+
<%= f.text_field :mail, :required => true %>
+
<%= f.select :language, lang_options_for_select %>
<% if Setting.openid? %>
-
<%=l(:field_identity_url)%>
-<%= text_field 'user', 'identity_url' %>
+
<%= f.text_field :identity_url %>
<% end %>
<% @user.custom_field_values.select {|v| v.editable? || v.required?}.each do |value| %>
<%= custom_field_tag_with_label :user, value %>
<% end %>
-
<%= submit_tag l(:button_submit) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/activities/index.html.erb
--- a/app/views/activities/index.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/activities/index.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,4 +1,4 @@
-<%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)) %>
+<%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)).html_safe %>
<%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %>
@@ -40,7 +40,7 @@
<% end %>
<% content_for :sidebar do %>
-<% form_tag({}, :method => :get) do %>
+<%= form_tag({}, :method => :get) do %>
<%= l(:label_activity) %>
<% @activity.event_types.each do |t| %>
<%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/admin/_menu.html.erb
--- a/app/views/admin/_menu.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/admin/_menu.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,5 +1,3 @@
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/admin/_no_data.html.erb
--- a/app/views/admin/_no_data.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/admin/_no_data.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,5 +1,5 @@
-<% form_tag({:action => 'default_configuration'}) do %>
+<%= form_tag({:action => 'default_configuration'}) do %>
<%= simple_format(l(:text_no_configuration_data)) %>
<%= l(:field_language) %>:
<%= select_tag 'lang', options_for_select(lang_options_for_select(false), current_language.to_s) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/admin/info.html.erb
--- a/app/views/admin/info.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/admin/info.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<%=l(:label_information_plural)%>
-
<%= Redmine::Info.versioned_name %> (<%= @db_adapter_name %>)
+
<%= Redmine::Info.versioned_name %>
<% @checklist.each do |label, result| %>
@@ -11,5 +11,9 @@
<% end %>
+
+
+
<%= Redmine::Info.environment %>
+
<% html_title(l(:label_information_plural)) -%>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/admin/projects.html.erb
--- a/app/views/admin/projects.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/admin/projects.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -4,7 +4,7 @@
<%=l(:label_project_plural)%>
-<% form_tag({}, :method => :get) do %>
+<%= form_tag({}, :method => :get) do %>
<%= l(:label_filter_plural) %>
<%= l(:field_status) %> :
<%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %>
@@ -27,14 +27,14 @@
<% project_tree(@projects) do |project, level| %>
<%= project.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>">
- <%= link_to_project(project, {:action => 'settings'}, :title => project.short_description) %>
+ <%= link_to_project(project, {:action => (project.active? ? 'settings' : 'show')}, :title => project.short_description) %>
<%= checked_image project.is_public? %>
<%= format_date(project.created_on) %>
- <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %>
- <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if !project.active? && (project.parent.nil? || project.parent.active?) %>
+ <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-lock') unless project.archived? %>
+ <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if project.archived? && (project.parent.nil? || !project.parent.archived?) %>
<%= link_to(l(:button_copy), { :controller => 'projects', :action => 'copy', :id => project }, :class => 'icon icon-copy') %>
- <%= link_to(l(:button_delete), project_destroy_confirm_path(project), :class => 'icon icon-del') %>
+ <%= link_to(l(:button_delete), project_path(project), :method => :delete, :class => 'icon icon-del') %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/attachments/_form.html.erb
--- a/app/views/attachments/_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/attachments/_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,11 +1,18 @@
+<% if defined?(container) && container && container.saved_attachments %>
+ <% container.saved_attachments.each_with_index do |attachment, i| %>
+
+ <%= h(attachment.filename) %> (<%= number_to_human_size(attachment.filesize) %>)
+ <%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.id}.#{attachment.digest}" %>
+
+ <% end %>
+<% end %>
- <%= file_field_tag 'attachments[1][file]', :size => 30, :id => nil, :class => 'file',
+ <%= file_field_tag 'attachments[1][file]', :id => nil, :class => 'file',
:onchange => "checkFileSize(this, #{Setting.attachment_max_size.to_i.kilobytes}, '#{escape_javascript(l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)))}');" -%>
- <%= l(:label_optional_description) %><%= text_field_tag 'attachments[1][description]', '', :size => 60, :id => nil, :class => 'description' %>
+ <%= text_field_tag 'attachments[1][description]', '', :id => nil, :class => 'description', :maxlength => 255, :placeholder => l(:label_optional_description) %>
<%= link_to_function(image_tag('delete.png'), 'removeFileField(this)', :title => (l(:button_delete))) %>
-<%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %>
-(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
-
+<%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;', :class => 'add_attachment' %>
+(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/attachments/_links.html.erb
--- a/app/views/attachments/_links.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/attachments/_links.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,11 +1,16 @@
<% for attachment in attachments %>
-
<%= link_to_attachment attachment, :class => 'icon icon-attachment' -%>
-<%= h(" - #{attachment.description}") unless attachment.description.blank? %>
+
<%= link_to_attachment attachment, :class => 'icon icon-attachment', :download => true -%>
+ <% if attachment.is_text? %>
+ <%= link_to image_tag('magnifier.png'),
+ :controller => 'attachments', :action => 'show',
+ :id => attachment, :filename => attachment.filename %>
+ <% end %>
+ <%= h(" - #{attachment.description}") unless attachment.description.blank? %>
(<%= number_to_human_size attachment.filesize %>)
<% if options[:deletable] %>
<%= link_to image_tag('delete.png'), attachment_path(attachment),
- :confirm => l(:text_are_you_sure),
+ :data => {:confirm => l(:text_are_you_sure)},
:method => :delete,
:class => 'delete',
:title => l(:button_delete) %>
@@ -15,4 +20,14 @@
<% end %>
<% end %>
+<% if defined?(thumbnails) && thumbnails %>
+ <% images = attachments.select(&:thumbnailable?) %>
+ <% if images.any? %>
+
+ <% images.each do |attachment| %>
+
<%= thumbnail_tag(attachment) %>
+ <% end %>
+
+ <% end %>
+<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/attachments/diff.html.erb
--- a/app/views/attachments/diff.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/attachments/diff.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -6,16 +6,14 @@
<%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%>
(<%= number_to_human_size @attachment.filesize %>)
-
-<% form_tag({}, :method => 'get') do %>
- <%= l(:label_view_diff) %>
- <%= select_tag 'type',
- options_for_select(
- [[l(:label_diff_inline), "inline"], [l(:label_diff_side_by_side), "sbs"]], @diff_type),
- :onchange => "if (this.value != '') {this.form.submit()}" %>
+<%= form_tag({}, :method => 'get') do %>
+
+ <%= l(:label_view_diff) %>:
+ <%= radio_button_tag 'type', 'inline', @diff_type != 'sbs', :onchange => "this.form.submit()" %> <%= l(:label_diff_inline) %>
+ <%= radio_button_tag 'type', 'sbs', @diff_type == 'sbs', :onchange => "this.form.submit()" %> <%= l(:label_diff_side_by_side) %>
+
<% end %>
-
-<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %>
+<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type, :diff_style => nil} %>
<% html_title @attachment.filename %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/attachments/upload.api.rsb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/attachments/upload.api.rsb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,3 @@
+api.upload do
+ api.token @attachment.token
+end
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/auth_sources/_form_auth_source_ldap.html.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/auth_sources/_form_auth_source_ldap.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,50 @@
+<%= error_messages_for 'auth_source' %>
+
+
+
+
<%=l(:field_name)%> *
+<%= text_field 'auth_source', 'name' %>
+
+
<%=l(:field_host)%> *
+<%= text_field 'auth_source', 'host' %>
+
+
<%=l(:field_port)%> *
+<%= text_field 'auth_source', 'port', :size => 6 %> <%= check_box 'auth_source', 'tls' %> LDAPS
+
+
<%=l(:field_account)%>
+<%= text_field 'auth_source', 'account' %>
+
+
<%=l(:field_password)%>
+<%= password_field 'auth_source', 'account_password', :name => 'ignore',
+ :value => ((@auth_source.new_record? || @auth_source.account_password.blank?) ? '' : ('x'*15)),
+ :onfocus => "this.value=''; this.name='auth_source[account_password]';",
+ :onchange => "this.name='auth_source[account_password]';" %>
+
+
<%=l(:field_base_dn)%> *
+<%= text_field 'auth_source', 'base_dn', :size => 60 %>
+
+
<%=l(:field_auth_source_ldap_filter)%>
+<%= text_field 'auth_source', 'filter', :size => 60 %>
+
+
<%=l(:field_timeout)%>
+<%= text_field 'auth_source', 'timeout', :size => 4 %>
+
+
<%=l(:field_onthefly)%>
+<%= check_box 'auth_source', 'onthefly_register' %>
+
+
+<%=l(:label_attribute_plural)%>
+<%=l(:field_login)%> *
+<%= text_field 'auth_source', 'attr_login', :size => 20 %>
+
+<%=l(:field_firstname)%>
+<%= text_field 'auth_source', 'attr_firstname', :size => 20 %>
+
+<%=l(:field_lastname)%>
+<%= text_field 'auth_source', 'attr_lastname', :size => 20 %>
+
+<%=l(:field_mail)%>
+<%= text_field 'auth_source', 'attr_mail', :size => 20 %>
+
+
+
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/auth_sources/edit.html.erb
--- a/app/views/auth_sources/edit.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/auth_sources/edit.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,7 +1,6 @@
<%=l(:label_auth_source)%> (<%= h(@auth_source.auth_method_name) %>)
-<% form_tag({:action => 'update', :id => @auth_source}, :class => "tabular") do %>
- <%= render :partial => 'form' %>
+<%= form_tag({:action => 'update', :id => @auth_source}, :method => :put, :class => "tabular") do %>
+ <%= render :partial => auth_source_partial_name(@auth_source) %>
<%= submit_tag l(:button_save) %>
<% end %>
-
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/auth_sources/index.html.erb
--- a/app/views/auth_sources/index.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/auth_sources/index.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -20,12 +20,8 @@
<%= h source.host %>
<%= h source.users.count %>
- <%= link_to l(:button_test), :action => 'test_connection', :id => source %>
- <%= link_to l(:button_delete), { :action => 'destroy', :id => source },
- :method => :post,
- :confirm => l(:text_are_you_sure),
- :class => 'icon icon-del',
- :disabled => source.users.any? %>
+ <%= link_to l(:button_test), {:action => 'test_connection', :id => source}, :class => 'icon icon-test' %>
+ <%= delete_link auth_source_path(source) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/auth_sources/new.html.erb
--- a/app/views/auth_sources/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/auth_sources/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,7 @@
<%=l(:label_auth_source_new)%> (<%= h(@auth_source.auth_method_name) %>)
-<% form_tag({:action => 'create'}, :class => "tabular") do %>
- <%= render :partial => 'form' %>
+<%= form_tag({:action => 'create'}, :class => "tabular") do %>
+ <%= hidden_field_tag 'type', @auth_source.type %>
+ <%= render :partial => auth_source_partial_name(@auth_source) %>
<%= submit_tag l(:button_create) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/auto_completes/issues.html.erb
--- a/app/views/auto_completes/issues.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/auto_completes/issues.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,9 +1,7 @@
-
-<% if @issues.any? -%>
- <% @issues.each do |issue| -%>
- <%= content_tag 'li', h("#{issue.tracker} ##{issue.id}: #{issue.subject}"), :id => issue.id %>
- <% end -%>
-<% else -%>
- <%= content_tag("li", l(:label_none), :style => 'display:none') %>
-<% end -%>
-
+<%= raw @issues.map {|issue| {
+ 'id' => issue.id,
+ 'label' => "#{issue.tracker} ##{issue.id}: #{truncate issue.subject.to_s, :length => 60}",
+ 'value' => issue.id
+ }
+ }.to_json
+%>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/boards/_form.html.erb
--- a/app/views/boards/_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/boards/_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,8 +1,9 @@
-<%= error_messages_for 'board' %>
+<%= error_messages_for @board %>
-
-
+
<%= f.text_field :name, :required => true %>
<%= f.text_field :description, :required => true, :size => 80 %>
+<% if @board.valid_parents.any? %>
+
<%= f.select :parent_id, boards_options_for_select(@board.valid_parents), :include_blank => true, :label => :field_board_parent %>
+<% end %>
-
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/boards/edit.html.erb
--- a/app/views/boards/edit.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/boards/edit.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<%= l(:label_board) %>
-<% labelled_tabular_form_for :board, @board, :url => {:action => 'edit', :id => @board} do |f| %>
+<%= labelled_form_for @board, :url => project_board_path(@project, @board) do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= submit_tag l(:button_save) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/boards/index.html.erb
--- a/app/views/boards/index.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/boards/index.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -8,21 +8,19 @@
<%= l(:label_message_last) %>
-<% for board in @boards %>
+<% Board.board_tree(@boards) do |board, level| %>
-
+
<%= link_to h(board.name), {:action => 'show', :id => board}, :class => "board" %>
<%=h board.description %>
- <%= board.topics_count %>
- <%= board.messages_count %>
-
-
+ <%= board.topics_count %>
+ <%= board.messages_count %>
+
<% if board.last_message %>
<%= authoring board.last_message.created_on, board.last_message.author %>
<%= link_to_message board.last_message %>
<% end %>
-
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/boards/new.html.erb
--- a/app/views/boards/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/boards/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<%= l(:label_board_new) %>
-<% labelled_tabular_form_for :board, @board, :url => {:action => 'new'} do |f| %>
+<%= labelled_form_for @board, :url => project_boards_path(@project) do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= submit_tag l(:button_create) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/boards/show.html.erb
--- a/app/views/boards/show.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/boards/show.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,27 +1,21 @@
-<%= breadcrumb link_to(l(:label_board_plural), {:controller => 'boards', :action => 'index', :project_id => @project}) %>
+<%= board_breadcrumb(@board) %>
<%= link_to_if_authorized l(:label_message_new),
{:controller => 'messages', :action => 'new', :board_id => @board},
:class => 'icon icon-add',
- :onclick => 'Element.show("add-message"); Form.Element.focus("message_subject"); return false;' %>
+ :onclick => 'showAndScrollTo("add-message", "message_subject"); return false;' %>
<%= watcher_tag(@board, User.current) %>
<% if authorize_for('messages', 'new') %>
<%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> » <%= l(:label_message_new) %>
-<% form_for :message, @message, :url => {:controller => 'messages', :action => 'new', :board_id => @board}, :html => {:multipart => true, :id => 'message-form'} do |f| %>
+<%= form_for @message, :url => {:controller => 'messages', :action => 'new', :board_id => @board}, :html => {:multipart => true, :id => 'message-form'} do |f| %>
<%= render :partial => 'messages/form', :locals => {:f => f} %>
<%= submit_tag l(:button_create) %>
- <%= link_to_remote l(:label_preview),
- { :url => { :controller => 'messages', :action => 'preview', :board_id => @board },
- :method => 'post',
- :update => 'preview',
- :with => "Form.serialize('message-form')",
- :complete => "Element.scrollTo('preview')"
- }, :accesskey => accesskey(:preview) %> |
- <%= link_to l(:button_cancel), "#", :onclick => 'Element.hide("add-message")' %>
+ <%= preview_link({:controller => 'messages', :action => 'preview', :board_id => @board}, 'message-form') %> |
+ <%= link_to l(:button_cancel), "#", :onclick => '$("#add-message").hide(); return false;' %>
<% end %>
<% end %>
@@ -43,9 +37,9 @@
<% @topics.each do |topic| %>
<%= link_to h(topic.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => topic } %>
- <%= link_to_user(topic.author) %>
- <%= format_time(topic.created_on) %>
- <%= topic.replies_count %>
+ <%= link_to_user(topic.author) %>
+ <%= format_time(topic.created_on) %>
+ <%= topic.replies_count %>
<% if topic.last_reply %>
<%= authoring topic.last_reply.created_on, topic.last_reply.author %>
@@ -69,5 +63,4 @@
<% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@project}: #{@board}") %>
- <%= stylesheet_link_tag 'scm' %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/calendars/show.html.erb
--- a/app/views/calendars/show.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/calendars/show.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,7 @@
<%= @query.new_record? ? l(:label_calendar) : h(@query.name) %>
-<% form_tag({:controller => 'calendars', :action => 'show', :project_id => @project}, :method => :get, :id => 'query_form') do %>
+<%= form_tag({:controller => 'calendars', :action => 'show', :project_id => @project},
+ :method => :get, :id => 'query_form') do %>
<%= hidden_field_tag 'set_filter', '1' %>
">
<%= l(:label_filter_plural) %>
@@ -19,7 +20,7 @@
<%= label_tag('year', l(:label_year)) %>
<%= select_year(@year, :prefix => "year", :discard_type => true) %>
-<%= link_to_function l(:button_apply), '$("query_form").submit()', :class => 'icon icon-checked' %>
+<%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %>
<%= link_to l(:button_clear), { :project_id => @project, :set_filter => 1 }, :class => 'icon icon-reload' %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/common/_calendar.html.erb
--- a/app/views/common/_calendar.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/common/_calendar.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -6,7 +6,7 @@
<% day = calendar.startdt
while day <= calendar.enddt %>
-<%= "#{(day+(11-day.cwday)%7).cweek} " if day.cwday == calendar.first_wday %>
+<%= ("#{(day+(11-day.cwday)%7).cweek} ".html_safe) if day.cwday == calendar.first_wday %>
<%= day.day %>
<% calendar.events_on(day).each do |i| %>
@@ -24,7 +24,7 @@
<% end %>
<% end %>
-<%= ' ' if day.cwday==calendar.last_wday and day!=calendar.enddt %>
+<%= ' '.html_safe if day.cwday==calendar.last_wday and day!=calendar.enddt %>
<% day = day + 1
end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/common/_diff.html.erb
--- a/app/views/common/_diff.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/common/_diff.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,7 @@
<% diff = Redmine::UnifiedDiff.new(
diff, :type => diff_type,
- :max_lines => Setting.diff_max_lines_displayed.to_i) -%>
+ :max_lines => Setting.diff_max_lines_displayed.to_i,
+ :style => diff_style) -%>
<% diff.each do |table_file| -%>
<% end -%>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/common/_file.html.erb
--- a/app/views/common/_file.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/common/_file.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -2,13 +2,13 @@
<% line_num = 1 %>
-<% syntax_highlight(filename, Redmine::CodesetUtil.to_utf8_by_setting(content)).each_line do |line| %>
+<% syntax_highlight_lines(filename, Redmine::CodesetUtil.to_utf8_by_setting(content)).each do |line| %>
<%= line_num %>
- <%= line %>
+ <%= line.html_safe %>
<% line_num += 1 %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/common/_tabs.html.erb
--- a/app/views/common/_tabs.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/common/_tabs.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -16,8 +16,8 @@
<% tabs.each do |tab| -%>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/common/error.html.erb
--- a/app/views/common/error.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/common/error.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -3,6 +3,6 @@
<% if @message.present? %>
<%=h @message %>
<% end %>
-Back
+<%= l(:button_back) %>
<% html_title @status %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/common/error_messages.api.rsb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/common/error_messages.api.rsb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,5 @@
+api.array :errors do
+ @error_messages.each do |message|
+ api.error message
+ end
+end
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/context_menus/issues.html.erb
--- a/app/views/context_menus/issues.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/context_menus/issues.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -5,17 +5,17 @@
<%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},
:class => 'icon-edit', :disabled => !@can[:edit] %>
<% else %>
- <%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id)},
+ <%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'bulk_edit', :ids => @issue_ids},
:class => 'icon-edit', :disabled => !@can[:edit] %>
<% end %>
<% if @allowed_statuses.present? %>
-
+
- <% @statuses.each do |s| -%>
- <%= context_menu_link h(s.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {:status_id => s}, :back_url => @back}, :method => :post,
- :selected => (@issue && s == @issue.status), :disabled => !(@can[:update] && @allowed_statuses.include?(s)) %>
+ <% @allowed_statuses.each do |s| -%>
+ <%= context_menu_link h(s.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {:status_id => s}, :back_url => @back}, :method => :post,
+ :selected => (@issue && s == @issue.status), :disabled => !@can[:update] %>
<% end -%>
@@ -26,76 +26,97 @@
<% @trackers.each do |t| -%>
- <%= context_menu_link h(t.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post,
+ <%= context_menu_link h(t.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'tracker_id' => t}, :back_url => @back}, :method => :post,
:selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %>
<% end -%>
<% end %>
+ <% if @safe_attributes.include?('priority_id') -%>
<% @priorities.each do |p| -%>
- <%= context_menu_link h(p.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post,
+ <%= context_menu_link h(p.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'priority_id' => p}, :back_url => @back}, :method => :post,
:selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
<% end -%>
+ <% end %>
- <% #TODO: allow editing versions when multiple projects %>
- <% unless @project.nil? || @project.shared_versions.open.empty? -%>
+ <% if @safe_attributes.include?('fixed_version_id') && @versions.any? -%>
- <% @project.shared_versions.open.sort.each do |v| -%>
- <%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post,
+ <% @versions.sort.each do |v| -%>
+ <%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'fixed_version_id' => v}, :back_url => @back}, :method => :post,
:selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %>
<% end -%>
- <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post,
+ <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'fixed_version_id' => 'none'}, :back_url => @back}, :method => :post,
:selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %>
<% end %>
- <% if @assignables.present? -%>
+
+ <% if @safe_attributes.include?('assigned_to_id') && @assignables.present? -%>
+ <% if @assignables.include?(User.current) %>
+ <%= context_menu_link "<< #{l(:label_me)} >>", {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'assigned_to_id' => User.current}, :back_url => @back}, :method => :post,
+ :disabled => !@can[:update] %>
+ <% end %>
<% @assignables.each do |u| -%>
- <%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post,
+ <%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'assigned_to_id' => u}, :back_url => @back}, :method => :post,
:selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %>
<% end -%>
- <%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post,
+ <%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'assigned_to_id' => 'none'}, :back_url => @back}, :method => :post,
:selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %>
<% end %>
- <% unless @project.nil? || @project.issue_categories.empty? -%>
+
+ <% if @safe_attributes.include?('category_id') && @project && @project.issue_categories.any? -%>
<% @project.issue_categories.each do |u| -%>
- <%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => u}, :back_url => @back}, :method => :post,
+ <%= context_menu_link h(u.name), {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'category_id' => u}, :back_url => @back}, :method => :post,
:selected => (@issue && u == @issue.category), :disabled => !@can[:update] %>
<% end -%>
- <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post,
+ <%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'category_id' => 'none'}, :back_url => @back}, :method => :post,
:selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %>
<% end -%>
- <% if Issue.use_field_for_done_ratio? %>
+ <% if @safe_attributes.include?('done_ratio') && Issue.use_field_for_done_ratio? %>
<% (0..10).map{|x|x*10}.each do |p| -%>
- <%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post,
+ <%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post,
:selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
<% end -%>
<% end %>
+ <% @options_by_custom_field.each do |field, options| %>
+
+
+
+ <% options.each do |text, value| %>
+ <%= bulk_update_custom_field_context_menu_link(field, text, value || text) %>
+ <% end %>
+ <% unless field.is_required? %>
+ <%= bulk_update_custom_field_context_menu_link(field, l(:label_none), '') %>
+ <% end %>
+
+
+ <% end %>
+
<% if !@issue.nil? %>
<% if @can[:log_time] -%>
<%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue},
@@ -107,15 +128,14 @@
<% end %>
<% if @issue.present? %>
- <%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
- :class => 'icon-duplicate', :disabled => !@can[:copy] %>
-<% end %>
- <%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}),
- :class => 'icon-copy', :disabled => !@can[:move] %>
- <%= context_menu_link l(:button_move), new_issue_move_path(:ids => @issues.collect(&:id)),
- :class => 'icon-move', :disabled => !@can[:move] %>
- <%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id), :back_url => @back},
- :method => :post, :confirm => issues_destroy_confirmation_message(@issues), :class => 'icon-del', :disabled => !@can[:delete] %>
+ <%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue},
+ :class => 'icon-copy', :disabled => !@can[:copy] %>
+<% else %>
+ <%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'bulk_edit', :ids => @issue_ids, :copy => '1'},
+ :class => 'icon-copy', :disabled => !@can[:move] %>
+<% end %>
+ <%= context_menu_link l(:button_delete), issues_path(:ids => @issue_ids, :back_url => @back),
+ :method => :delete, :data => {:confirm => issues_destroy_confirmation_message(@issues)}, :class => 'icon-del', :disabled => !@can[:delete] %>
<%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/context_menus/time_entries.html.erb
--- a/app/views/context_menus/time_entries.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/context_menus/time_entries.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -14,10 +14,10 @@
<% @activities.each do |u| -%>
- <%= context_menu_link h(u.name), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => u}, :back_url => @back}, :method => :post,
+ <%= context_menu_link h(u.name), {:controller => 'timelog', :action => 'bulk_update', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => u}, :back_url => @back}, :method => :post,
:selected => (@time_entry && u == @time_entry.activity), :disabled => !@can[:edit] %>
<% end -%>
- <%= context_menu_link l(:label_none), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => 'none'}, :back_url => @back}, :method => :post,
+ <%= context_menu_link l(:label_none), {:controller => 'timelog', :action => 'bulk_update', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => 'none'}, :back_url => @back}, :method => :post,
:selected => (@time_entry && @time_entry.activity.nil?), :disabled => !@can[:edit] %>
@@ -28,6 +28,6 @@
<%= context_menu_link l(:button_delete),
{:controller => 'timelog', :action => 'destroy', :ids => @time_entries.collect(&:id), :back_url => @back},
- :method => :delete, :confirm => l(:text_time_entries_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %>
+ :method => :delete, :data => {:confirm => l(:text_time_entries_destroy_confirmation)}, :class => 'icon-del', :disabled => !@can[:delete] %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/custom_fields/_form.html.erb
--- a/app/views/custom_fields/_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/custom_fields/_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,87 +1,40 @@
<%= error_messages_for 'custom_field' %>
-
-
-
-
<%= f.text_field :name, :required => true %>
-
<%= f.select :field_format, custom_field_formats_for_select(@custom_field), {}, :onchange => "toggle_custom_field_format();",
- :disabled => !@custom_field.new_record? %>
+<% unless @custom_field.format_in? 'list', 'bool', 'date', 'user', 'version' %>
<%=l(:label_min_max_length)%>
<%= f.text_field :min_length, :size => 5, :no_label => true %> -
<%= f.text_field :max_length, :size => 5, :no_label => true %> (<%=l(:text_min_max_length_info)%>)
<%= f.text_field :regexp, :size => 50 %> (<%=l(:text_regexp_info)%>)
+<% end %>
+
+<% if @custom_field.format_in? 'list' %>
<%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"), :rows => 15 %>
- <%= l(:text_custom_field_possible_values_info) %>
+ <%= l(:text_custom_field_possible_values_info) %>
+<% end %>
+
+<% unless @custom_field.format_in? 'user', 'version' %>
<%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %>
+<% end %>
+
<%= call_hook(:view_custom_fields_form_upper_box, :custom_field => @custom_field, :form => f) %>
-
+
<% case @custom_field.class.name
when "IssueCustomField" %>
<%=l(:label_tracker_plural)%>
- <% for tracker in @trackers %>
+ <% Tracker.sorted.all.each do |tracker| %>
<%= check_box_tag "custom_field[tracker_ids][]",
tracker.id,
(@custom_field.trackers.include? tracker),
@@ -102,11 +55,21 @@
<%= f.check_box :is_required %>
<%= f.check_box :visible %>
<%= f.check_box :editable %>
+ <%= f.check_box :is_filter %>
<% when "ProjectCustomField" %>
<%= f.check_box :is_required %>
<%= f.check_box :visible %>
<%= f.check_box :searchable %>
+ <%= f.check_box :is_filter %>
+
+<% when "VersionCustomField" %>
+ <%= f.check_box :is_required %>
+ <%= f.check_box :is_filter %>
+
+<% when "GroupCustomField" %>
+ <%= f.check_box :is_required %>
+ <%= f.check_box :is_filter %>
<% when "TimeEntryCustomField" %>
<%= f.check_box :is_required %>
@@ -117,4 +80,3 @@
<% end %>
<%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %>
-<%= javascript_tag "toggle_custom_field_format();" %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/custom_fields/_index.html.erb
--- a/app/views/custom_fields/_index.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/custom_fields/_index.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -13,23 +13,20 @@
<% (@custom_fields_by_type[tab[:name]] || []).sort.each do |custom_field| -%>
">
- <%= link_to h(custom_field.name), :action => 'edit', :id => custom_field %>
+ <%= link_to h(custom_field.name), edit_custom_field_path(custom_field) %>
<%= l(Redmine::CustomFieldFormat.label_for(custom_field.field_format)) %>
<%= checked_image custom_field.is_required? %>
<% if tab[:name] == 'IssueCustomField' %>
<%= checked_image custom_field.is_for_all? %>
<%= l(:label_x_projects, :count => custom_field.projects.count) if custom_field.is_a? IssueCustomField and !custom_field.is_for_all? %>
<% end %>
- <%= reorder_links('custom_field', {:action => 'edit', :id => custom_field}) %>
+ <%= reorder_links('custom_field', {:action => 'update', :id => custom_field}, :put) %>
- <%= link_to(l(:button_delete), { :action => 'destroy', :id => custom_field },
- :method => :post,
- :confirm => l(:text_are_you_sure),
- :class => 'icon icon-del') %>
+ <%= delete_link custom_field_path(custom_field) %>
<% end; reset_cycle %>
-
<%= link_to l(:label_custom_field_new), {:action => 'new', :type => tab[:name]}, :class => 'icon icon-add' %>
+
<%= link_to l(:label_custom_field_new), new_custom_field_path(:type => tab[:name]), :class => 'icon icon-add' %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/custom_fields/edit.html.erb
--- a/app/views/custom_fields/edit.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/custom_fields/edit.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -2,7 +2,7 @@
» <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
» <%=h @custom_field.name %>
-<% labelled_tabular_form_for :custom_field, @custom_field, :url => { :action => "edit", :id => @custom_field } do |f| %>
+<%= labelled_form_for :custom_field, @custom_field, :url => custom_field_path(@custom_field), :html => {:method => :put, :id => 'custom_field_form'} do |f| %>
<%= render :partial => 'form', :locals => { :f => f } %>
<%= submit_tag l(:button_save) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/custom_fields/new.html.erb
--- a/app/views/custom_fields/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/custom_fields/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -2,8 +2,18 @@
» <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
» <%= l(:label_custom_field_new) %>
-<% labelled_tabular_form_for :custom_field, @custom_field, :url => { :action => "new" } do |f| %>
+<%= labelled_form_for :custom_field, @custom_field, :url => custom_fields_path, :html => {:id => 'custom_field_form'} do |f| %>
<%= render :partial => 'form', :locals => { :f => f } %>
<%= hidden_field_tag 'type', @custom_field.type %>
<%= submit_tag l(:button_save) %>
<% end %>
+
+<%= javascript_tag do %>
+$('#custom_field_field_format').change(function(){
+ $.ajax({
+ url: '<%= new_custom_field_path(:format => 'js') %>',
+ type: 'get',
+ data: $('#custom_field_form').serialize()
+ });
+});
+<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/custom_fields/new.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/custom_fields/new.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,1 @@
+$('#content').html('<%= escape_javascript(render :template => 'custom_fields/new', :layout => nil, :formats => [:html]) %>')
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/documents/_document.html.erb
--- a/app/views/documents/_document.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/documents/_document.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,4 +1,4 @@
-
<%= link_to h(document.title), :controller => 'documents', :action => 'show', :id => document %>
+
<%= link_to h(document.title), document_path(document) %>
<%= format_time(document.updated_on) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/documents/_form.html.erb
--- a/app/views/documents/_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/documents/_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,15 +1,15 @@
-<%= error_messages_for 'document' %>
-
-
-
<%=l(:field_category)%>
-<%= select('document', 'category_id', DocumentCategory.active.collect {|c| [c.name, c.id]}) %>
+<%= error_messages_for @document %>
-
<%=l(:field_title)%> *
-<%= text_field 'document', 'title', :size => 60 %>
-
-
<%=l(:field_description)%>
-<%= text_area 'document', 'description', :cols => 60, :rows => 15, :class => 'wiki-edit' %>
-
+
+
<%= f.select :category_id, DocumentCategory.active.collect {|c| [c.name, c.id]} %>
+
<%= f.text_field :title, :required => true, :size => 60 %>
+
<%= f.text_area :description, :cols => 60, :rows => 15, :class => 'wiki-edit' %>
<%= wikitoolbar_for 'document_description' %>
+
+<% if @document.new_record? %>
+
+
<%=l(:label_attachment_plural)%> <%= render :partial => 'attachments/form', :locals => {:container => @document} %>
+
+<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/documents/edit.html.erb
--- a/app/views/documents/edit.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/documents/edit.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,8 +1,8 @@
<%=l(:label_document)%>
-<% form_tag({:action => 'edit', :id => @document}, :class => "tabular") do %>
- <%= render :partial => 'form' %>
- <%= submit_tag l(:button_save) %>
+<%= labelled_form_for @document do |f| %>
+ <%= render :partial => 'form', :locals => {:f => f} %>
+
<%= submit_tag l(:button_save) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/documents/index.html.erb
--- a/app/views/documents/index.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/documents/index.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,19 +1,16 @@
-<%= link_to_if_authorized l(:label_document_new),
- {:controller => 'documents', :action => 'new', :project_id => @project},
- :class => 'icon icon-add',
- :onclick => 'Element.show("add-document"); Form.Element.focus("document_title"); return false;' %>
+<%= link_to l(:label_document_new), new_project_document_path(@project), :class => 'icon icon-add',
+ :onclick => 'showAndScrollTo("add-document", "document_title"); return false;' if User.current.allowed_to?(:manage_documents, @project) %>
<%=l(:label_document_new)%>
-<% form_tag({:controller => 'documents', :action => 'new', :project_id => @project}, :class => "tabular", :multipart => true) do %>
-<%= render :partial => 'documents/form' %>
-
-
<%=l(:label_attachment_plural)%> <%= render :partial => 'attachments/form' %>
-
-<%= submit_tag l(:button_create) %>
-<%= link_to l(:button_cancel), "#", :onclick => 'Element.hide("add-document")' %>
+<%= labelled_form_for @document, :url => project_documents_path(@project), :html => {:multipart => true} do |f| %>
+<%= render :partial => 'form', :locals => {:f => f} %>
+
+ <%= submit_tag l(:button_create) %>
+ <%= link_to l(:button_cancel), "#", :onclick => '$("#add-document").hide(); return false;' %>
+
<% end %>
@@ -27,13 +24,11 @@
<% end %>
<% content_for :sidebar do %>
-
<%= l(:label_sort_by, '') %>
- <% form_tag({}, :method => :get) do %>
-
<%= radio_button_tag 'sort_by', 'category', (@sort_by == 'category'), :onclick => 'this.form.submit();' %> <%= l(:field_category) %>
-
<%= radio_button_tag 'sort_by', 'date', (@sort_by == 'date'), :onclick => 'this.form.submit();' %> <%= l(:label_date) %>
-
<%= radio_button_tag 'sort_by', 'title', (@sort_by == 'title'), :onclick => 'this.form.submit();' %> <%= l(:field_title) %>
-
<%= radio_button_tag 'sort_by', 'author', (@sort_by == 'author'), :onclick => 'this.form.submit();' %> <%= l(:field_author) %>
- <% end %>
+
<%= l(:label_sort_by, '') %>
+ <%= link_to l(:field_category), {:sort_by => 'category'}, :class => (@sort_by == 'category' ? 'selected' :nil) %>
+ <%= link_to l(:label_date), {:sort_by => 'date'}, :class => (@sort_by == 'date' ? 'selected' :nil) %>
+ <%= link_to l(:field_title), {:sort_by => 'title'}, :class => (@sort_by == 'title' ? 'selected' :nil) %>
+ <%= link_to l(:field_author), {:sort_by => 'author'}, :class => (@sort_by == 'author' ? 'selected' :nil) %>
<% end %>
<% html_title(l(:label_document_plural)) -%>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/documents/new.html.erb
--- a/app/views/documents/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/documents/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,13 +1,6 @@
<%=l(:label_document_new)%>
-<% form_tag({:controller => 'documents', :action => 'new', :project_id => @project}, :class => "tabular", :multipart => true) do %>
-<%= render :partial => 'documents/form' %>
-
-
-
<%=l(:label_attachment_plural)%> <%= render :partial => 'attachments/form' %>
-
-
-<%= submit_tag l(:button_create) %>
+<%= labelled_form_for @document, :url => project_documents_path(@project), :html => {:multipart => true} do |f| %>
+ <%= render :partial => 'form', :locals => {:f => f} %>
+
<%= submit_tag l(:button_create) %>
<% end %>
-
-
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/documents/show.html.erb
--- a/app/views/documents/show.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/documents/show.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,8 @@
-<%= link_to_if_authorized l(:button_edit), {:controller => 'documents', :action => 'edit', :id => @document}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
-<%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy', :id => @document}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
+<% if User.current.allowed_to?(:manage_documents, @project) %>
+<%= link_to l(:button_edit), edit_document_path(@document), :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
+<%= delete_link document_path(@document) %>
+<% end %>
<%=h @document.title %>
@@ -15,9 +17,9 @@
<%= link_to_attachments @document %>
<% if authorize_for('documents', 'add_attachment') %>
-
<%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;",
+
<%= link_to l(:label_attachment_new), {}, :onclick => "$('#add_attachment_form').show(); return false;",
:id => 'attach_files_link' %>
- <% form_tag({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
+ <%= form_tag({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
<%= render :partial => 'attachments/form' %>
@@ -26,7 +28,3 @@
<% end %>
<% html_title @document.title -%>
-
-<% content_for :header_tags do %>
- <%= stylesheet_link_tag 'scm' %>
-<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/enumerations/_form.html.erb
--- a/app/views/enumerations/_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/enumerations/_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,19 +1,11 @@
<%= error_messages_for 'enumeration' %>
-
-
-<%= hidden_field 'enumeration', 'type' %>
-
<%=l(:field_name)%>
-<%= text_field 'enumeration', 'name' %>
+
+
<%= f.text_field :name %>
+
<%= f.check_box :active %>
+
<%= f.check_box :is_default %>
-
<%=l(:field_active)%>
-<%= check_box 'enumeration', 'active' %>
-
-
<%=l(:field_is_default)%>
-<%= check_box 'enumeration', 'is_default' %>
-
-
-<% @enumeration.custom_field_values.each do |value| %>
-
<%= custom_field_tag_with_label :enumeration, value %>
-<% end %>
+ <% @enumeration.custom_field_values.each do |value| %>
+
<%= custom_field_tag_with_label :enumeration, value %>
+ <% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/enumerations/destroy.html.erb
--- a/app/views/enumerations/destroy.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/enumerations/destroy.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,12 +1,12 @@
<%= l(@enumeration.option_name) %>: <%=h @enumeration %>
-<% form_tag({}) do %>
+<%= form_tag({}, :method => :delete) do %>
<%= l(:text_enumeration_destroy_question, @enumeration.objects_count) %>
<%= l(:text_enumeration_category_reassign_to) %>
-<%= select_tag 'reassign_to_id', ("--- #{l(:actionview_instancetag_blank_option)} --- " + options_from_collection_for_select(@enumerations, 'id', 'name')) %>
+<%= select_tag 'reassign_to_id', (content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") + options_from_collection_for_select(@enumerations, 'id', 'name')) %>
<%= submit_tag l(:button_apply) %>
-<%= link_to l(:button_cancel), :controller => 'enumerations', :action => 'index' %>
+<%= link_to l(:button_cancel), enumerations_path %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/enumerations/edit.html.erb
--- a/app/views/enumerations/edit.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/enumerations/edit.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
-
<%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> » <%=h @enumeration %>
+
<%= link_to l(@enumeration.option_name), enumerations_path %> » <%=h @enumeration %>
-<% form_tag({:action => 'update', :id => @enumeration}, :class => "tabular") do %>
- <%= render :partial => 'form' %>
+<%= labelled_form_for :enumeration, @enumeration, :url => enumeration_path(@enumeration), :html => {:method => :put} do |f| %>
+ <%= render :partial => 'form', :locals => {:f => f} %>
<%= submit_tag l(:button_save) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/enumerations/index.api.rsb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/enumerations/index.api.rsb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,9 @@
+api.array @klass.name.underscore.pluralize do
+ @enumerations.each do |enumeration|
+ api.__send__ @klass.name.underscore do
+ api.id enumeration.id
+ api.name enumeration.name
+ api.is_default enumeration.is_default
+ end
+ end
+end
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/enumerations/index.html.erb
--- a/app/views/enumerations/index.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/enumerations/index.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -15,15 +15,12 @@
<% enumerations.each do |enumeration| %>
- <%= link_to h(enumeration), :action => 'edit', :id => enumeration %>
+ <%= link_to h(enumeration), edit_enumeration_path(enumeration) %>
<%= checked_image enumeration.is_default? %>
<%= checked_image enumeration.active? %>
- <%= reorder_links('enumeration', {:action => 'update', :id => enumeration}) %>
+ <%= reorder_links('enumeration', {:action => 'update', :id => enumeration}, :put) %>
- <%= link_to l(:button_delete), { :action => 'destroy', :id => enumeration },
- :method => :post,
- :confirm => l(:text_are_you_sure),
- :class => 'icon icon-del' %>
+ <%= delete_link enumeration_path(enumeration) %>
<% end %>
@@ -31,7 +28,7 @@
<% reset_cycle %>
<% end %>
-
<%= link_to l(:label_enumeration_new), { :action => 'new', :type => klass.name } %>
+
<%= link_to l(:label_enumeration_new), new_enumeration_path(:type => klass.name) %>
<% end %>
<% html_title(l(:label_enumerations)) -%>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/enumerations/new.html.erb
--- a/app/views/enumerations/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/enumerations/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,7 @@
-
<%= link_to l(@enumeration.option_name), :controller => 'enumerations', :action => 'index' %> » <%=l(:label_enumeration_new)%>
+
<%= link_to l(@enumeration.option_name), enumerations_path %> » <%=l(:label_enumeration_new)%>
-<% form_tag({:action => 'create'}, :class => "tabular") do %>
- <%= render :partial => 'form' %>
+<%= labelled_form_for :enumeration, @enumeration, :url => enumerations_path do |f| %>
+ <%= f.hidden_field :type %>
+ <%= render :partial => 'form', :locals => {:f => f} %>
<%= submit_tag l(:button_create) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/files/index.html.erb
--- a/app/views/files/index.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/files/index.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -34,7 +34,7 @@
<%= file.digest %>
<%= link_to(image_tag('delete.png'), attachment_path(file),
- :confirm => l(:text_are_you_sure), :method => :delete) if delete_allowed %>
+ :data => {:confirm => l(:text_are_you_sure)}, :method => :delete) if delete_allowed %>
<% end
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/files/new.html.erb
--- a/app/views/files/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/files/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,8 +1,8 @@
<%=l(:label_attachment_new)%>
<%= error_messages_for 'attachment' %>
+<%= form_tag(project_files_path(@project), :multipart => true, :class => "tabular") do %>
-<% form_tag(project_files_path(@project), :multipart => true, :class => "tabular") do %>
<% if @versions.any? %>
<%=l(:field_version)%>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/gantts/show.html.erb
--- a/app/views/gantts/show.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/gantts/show.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,7 +1,10 @@
<% @gantt.view = self %>
<%= @query.new_record? ? l(:label_gantt) : h(@query.name) %>
-<% form_tag({:controller => 'gantts', :action => 'show', :project_id => @project, :month => params[:month], :year => params[:year], :months => params[:months]}, :method => :get, :id => 'query_form') do %>
+<%= form_tag({:controller => 'gantts', :action => 'show',
+ :project_id => @project, :month => params[:month],
+ :year => params[:year], :months => params[:months]},
+ :method => :get, :id => 'query_form') do %>
<%= hidden_field_tag 'set_filter', '1' %>
">
<%= l(:label_filter_plural) %>
@@ -22,144 +25,211 @@
<%= select_year(@gantt.year_from, :prefix => "year", :discard_type => true) %>
<%= hidden_field_tag 'zoom', @gantt.zoom %>
-<%= link_to_function l(:button_apply), '$("query_form").submit()', :class => 'icon icon-checked' %>
-<%= link_to l(:button_clear), { :project_id => @project, :set_filter => 1 }, :class => 'icon icon-reload' %>
+<%= link_to_function l(:button_apply), '$("#query_form").submit()',
+ :class => 'icon icon-checked' %>
+<%= link_to l(:button_clear), { :project_id => @project, :set_filter => 1 },
+ :class => 'icon icon-reload' %>
<% end %>
<%= error_messages_for 'query' %>
<% if @query.valid? %>
-<% zoom = 1
-@gantt.zoom.times { zoom = zoom * 2 }
+<%
+ zoom = 1
+ @gantt.zoom.times { zoom = zoom * 2 }
-subject_width = 330
-header_heigth = 18
+ subject_width = 330
+ header_heigth = 18
-headers_height = header_heigth
-show_weeks = false
-show_days = false
+ headers_height = header_heigth
+ show_weeks = false
+ show_days = false
-if @gantt.zoom >1
+ if @gantt.zoom > 1
show_weeks = true
- headers_height = 2*header_heigth
+ headers_height = 2 * header_heigth
if @gantt.zoom > 2
show_days = true
- headers_height = 3*header_heigth
+ headers_height = 3 * header_heigth
end
-end
+ end
-# Width of the entire chart
-g_width = (@gantt.date_to - @gantt.date_from + 1)*zoom
-
-@gantt.render(:top => headers_height + 8, :zoom => zoom, :g_width => g_width, :subject_width => subject_width)
-
-g_height = [(20 * (@gantt.number_of_rows + 6))+150, 206].max
-t_height = g_height + headers_height
-
-
+ # Width of the entire chart
+ g_width = ((@gantt.date_to - @gantt.date_from + 1) * zoom).to_i
+ @gantt.render(:top => headers_height + 8,
+ :zoom => zoom,
+ :g_width => g_width,
+ :subject_width => subject_width)
+ g_height = [(20 * (@gantt.number_of_rows + 6)) + 150, 206].max
+ t_height = g_height + headers_height
%>
<% if @gantt.truncated %>
<%= l(:notice_gantt_chart_truncated, :max => @gantt.max_rows) %>
<% end %>
-
+
+ <%
+ style = ""
+ style += "position:relative;"
+ style += "height: #{t_height + 24}px;"
+ style += "width: #{subject_width + 1}px;"
+ %>
+ <%= content_tag(:div, :style => style) do %>
+ <%
+ style = ""
+ style += "right:-2px;"
+ style += "width: #{subject_width}px;"
+ style += "height: #{headers_height}px;"
+ style += 'background: #eee;'
+ %>
+ <%= content_tag(:div, "", :style => style, :class => "gantt_hdr") %>
+ <%
+ style = ""
+ style += "right:-2px;"
+ style += "width: #{subject_width}px;"
+ style += "height: #{t_height}px;"
+ style += 'border-left: 1px solid #c0c0c0;'
+ style += 'overflow: hidden;'
+ %>
+ <%= content_tag(:div, "", :style => style, :class => "gantt_hdr") %>
+ <%= content_tag(:div, :class => "gantt_subjects") do %>
+ <%= @gantt.subjects.html_safe %>
+ <% end %>
+ <% end %>
+
-
-
-
+
+
+<%
+ style = ""
+ style += "width: #{g_width - 1}px;"
+ style += "height: #{headers_height}px;"
+ style += 'background: #eee;'
+%>
+<%= content_tag(:div, ' '.html_safe, :style => style, :class => "gantt_hdr") %>
-
-<%= @gantt.subjects.html_safe %>
-
+<% ###### Months headers ###### %>
+<%
+ month_f = @gantt.date_from
+ left = 0
+ height = (show_weeks ? header_heigth : header_heigth + g_height)
+%>
+<% @gantt.months.times do %>
+ <%
+ width = (((month_f >> 1) - month_f) * zoom - 1).to_i
+ style = ""
+ style += "left: #{left}px;"
+ style += "width: #{width}px;"
+ style += "height: #{height}px;"
+ %>
+ <%= content_tag(:div, :style => style, :class => "gantt_hdr") do %>
+ <%= link_to h("#{month_f.year}-#{month_f.month}"),
+ @gantt.params.merge(:year => month_f.year, :month => month_f.month),
+ :title => "#{month_name(month_f.month)} #{month_f.year}" %>
+ <% end %>
+ <%
+ left = left + width + 1
+ month_f = month_f >> 1
+ %>
+<% end %>
-
-
-
+<% ###### Weeks headers ###### %>
+<% if show_weeks %>
+ <%
+ left = 0
+ height = (show_days ? header_heigth - 1 : header_heigth - 1 + g_height)
+ %>
+ <% if @gantt.date_from.cwday == 1 %>
+ <%
+ # @date_from is monday
+ week_f = @gantt.date_from
+ %>
+ <% else %>
+ <%
+ # find next monday after @date_from
+ week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1)
+ width = (7 - @gantt.date_from.cwday + 1) * zoom - 1
+ style = ""
+ style += "left: #{left}px;"
+ style += "top: 19px;"
+ style += "width: #{width}px;"
+ style += "height: #{height}px;"
+ %>
+ <%= content_tag(:div, ' '.html_safe,
+ :style => style, :class => "gantt_hdr") %>
+ <% left = left + width + 1 %>
+ <% end %>
+ <% while week_f <= @gantt.date_to %>
+ <%
+ width = ((week_f + 6 <= @gantt.date_to) ?
+ 7 * zoom - 1 :
+ (@gantt.date_to - week_f + 1) * zoom - 1).to_i
+ style = ""
+ style += "left: #{left}px;"
+ style += "top: 19px;"
+ style += "width: #{width}px;"
+ style += "height: #{height}px;"
+ %>
+ <%= content_tag(:div, :style => style, :class => "gantt_hdr") do %>
+ <%= content_tag(:small) do %>
+ <%= week_f.cweek if width >= 16 %>
+ <% end %>
+ <% end %>
+ <%
+ left = left + width + 1
+ week_f = week_f + 7
+ %>
+ <% end %>
+<% end %>
-
-
-<%
-#
-# Months headers
-#
-month_f = @gantt.date_from
-left = 0
-height = (show_weeks ? header_heigth : header_heigth + g_height)
-@gantt.months.times do
- width = ((month_f >> 1) - month_f) * zoom - 1
+<% ###### Days headers ####### %>
+<% if show_days %>
+ <%
+ left = 0
+ height = g_height + header_heigth - 1
+ wday = @gantt.date_from.cwday
%>
-
- <%= link_to h("#{month_f.year}-#{month_f.month}"), @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%>
-
- <%
- left = left + width + 1
- month_f = month_f >> 1
-end %>
-
-<%
-#
-# Weeks headers
-#
-if show_weeks
- left = 0
- height = (show_days ? header_heigth-1 : header_heigth-1 + g_height)
- if @gantt.date_from.cwday == 1
- # @date_from is monday
- week_f = @gantt.date_from
- else
- # find next monday after @date_from
- week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1)
- width = (7 - @gantt.date_from.cwday + 1) * zoom-1
+ <% (@gantt.date_to - @gantt.date_from + 1).to_i.times do %>
+ <%
+ width = zoom - 1
+ style = ""
+ style += "left: #{left}px;"
+ style += "top:37px;"
+ style += "width: #{width}px;"
+ style += "height: #{height}px;"
+ style += "font-size:0.7em;"
+ clss = "gantt_hdr"
+ clss << " nwday" if @gantt.non_working_week_days.include?(wday)
%>
-
+ <%= content_tag(:div, :style => style, :class => clss) do %>
+ <%= day_letter(wday) %>
+ <% end %>
<%
- left = left + width+1
- end %>
- <%
- while week_f <= @gantt.date_to
- width = (week_f + 6 <= @gantt.date_to) ? 7 * zoom -1 : (@gantt.date_to - week_f + 1) * zoom-1
+ left = left + width + 1
+ wday = wday + 1
+ wday = 1 if wday > 7
%>
-
- <%= week_f.cweek if width >= 16 %>
-
- <%
- left = left + width+1
- week_f = week_f+7
- end
-end %>
-
-<%
-#
-# Days headers
-#
-if show_days
- left = 0
- height = g_height + header_heigth - 1
- wday = @gantt.date_from.cwday
- (@gantt.date_to - @gantt.date_from + 1).to_i.times do
- width = zoom - 1
- %>
-
5 %>" class="gantt_hdr">
- <%= day_name(wday).first %>
-
- <%
- left = left + width+1
- wday = wday + 1
- wday = 1 if wday > 7
- end
-end %>
+ <% end %>
+<% end %>
<%= @gantt.lines.html_safe %>
-<%
-#
-# Today red line (excluded from cache)
-#
-if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %>
-
+<% ###### Today red line (excluded from cache) ###### %>
+<% if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %>
+ <%
+ today_left = (((Date.today - @gantt.date_from + 1) * zoom).floor() - 1).to_i
+ style = ""
+ style += "position: absolute;"
+ style += "height: #{g_height}px;"
+ style += "top: #{headers_height + 1}px;"
+ style += "left: #{today_left}px;"
+ style += "width:10px;"
+ style += "border-left: 1px dashed red;"
+ %>
+ <%= content_tag(:div, ' '.html_safe, :style => style) %>
<% end %>
@@ -167,10 +237,16 @@
-
+
-<%= link_to_content_update("\xc2\xab " + l(:label_previous), params.merge(@gantt.params_previous)) %>
-<%= link_to_content_update(l(:label_next) + " \xc2\xbb", params.merge(@gantt.params_next)) %>
+
+ <%= link_to_content_update("\xc2\xab " + l(:label_previous),
+ params.merge(@gantt.params_previous)) %>
+
+
+ <%= link_to_content_update(l(:label_next) + " \xc2\xbb",
+ params.merge(@gantt.params_next)) %>
+
@@ -181,7 +257,7 @@
<% end # query.valid? %>
<% content_for :sidebar do %>
- <%= render :partial => 'issues/sidebar' %>
+ <%= render :partial => 'issues/sidebar' %>
<% end %>
<% html_title(l(:label_gantt)) -%>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/_form.html.erb
--- a/app/views/groups/_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/groups/_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,7 +1,7 @@
-<%= f.error_messages %>
+<%= error_messages_for @group %>
-
<%= f.text_field :lastname, :label => :field_name %>
+
<%= f.text_field :name %>
<% @group.custom_field_values.each do |value| %>
<%= custom_field_tag_with_label :group, value %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/_general.html.erb
--- a/app/views/groups/_general.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/groups/_general.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,4 +1,4 @@
-<% labelled_form_for @group do |f| %>
+<%= labelled_form_for @group do |f| %>
<%= render :partial => 'form', :locals => { :f => f } %>
<%= submit_tag l(:button_save) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/_memberships.html.erb
--- a/app/views/groups/_memberships.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/groups/_memberships.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -16,20 +16,28 @@
<%=h membership.project %>
<%=h membership.roles.sort.collect(&:to_s).join(', ') %>
- <% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @group, :membership_id => membership },
- :html => { :id => "member-#{membership.id}-roles-form", :style => 'display:none;'}) do %>
+ <%= form_for(:membership, :remote => true,
+ :url => { :action => 'edit_membership', :id => @group, :membership_id => membership },
+ :html => { :id => "member-#{membership.id}-roles-form", :style => 'display:none;'}) do %>
<% roles.each do |role| %>
<%= check_box_tag 'membership[role_ids][]', role.id, membership.roles.include?(role) %> <%=h role %>
<% end %>
<%= submit_tag l(:button_change) %>
- <%= link_to_function l(:button_cancel), "$('member-#{membership.id}-roles').show(); $('member-#{membership.id}-roles-form').hide(); return false;" %>
+ <%= link_to_function(
+ l(:button_cancel),
+ "$('#member-#{membership.id}-roles').show(); $('#member-#{membership.id}-roles-form').hide(); return false;"
+ ) %>
<% end %>
- <%= link_to_function l(:button_edit), "$('member-#{membership.id}-roles').hide(); $('member-#{membership.id}-roles-form').show(); return false;", :class => 'icon icon-edit' %>
- <%= link_to_remote l(:button_delete), { :url => { :controller => 'groups', :action => 'destroy_membership', :id => @group, :membership_id => membership },
- :method => :post },
- :class => 'icon icon-del' %>
+ <%= link_to_function(
+ l(:button_edit),
+ "$('#member-#{membership.id}-roles').hide(); $('#member-#{membership.id}-roles-form').show(); return false;",
+ :class => 'icon icon-edit'
+ ) %>
+ <%= delete_link({:controller => 'groups', :action => 'destroy_membership', :id => @group, :membership_id => membership},
+ :remote => true,
+ :method => :post) %>
<% end; reset_cycle %>
@@ -43,7 +51,7 @@
<% if projects.any? %>
<%=l(:label_project_new)%>
-<% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @group }) do %>
+<%= form_for(:membership, :remote => true, :url => { :action => 'edit_membership', :id => @group }) do %>
<%= label_tag "membership_project_id", l(:description_choose_project), :class => "hidden-for-sighted" %>
<%= select_tag 'membership[project_id]', options_for_membership_project_select(@group, projects) %>
<%= l(:label_role_plural) %>:
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/_users.html.erb
--- a/app/views/groups/_users.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/groups/_users.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -10,7 +10,7 @@
<%= link_to_user user %>
- <%= link_to_remote l(:button_delete), { :url => group_user_path(@group, :user_id => user), :method => :delete }, :class => 'icon icon-del' %>
+ <%= delete_link group_user_path(@group, :user_id => user), :remote => true %>
<% end %>
@@ -24,17 +24,12 @@
<% users = User.active.not_in_group(@group).all(:limit => 100) %>
<% if users.any? %>
- <% remote_form_for(@group, :url => group_users_path(@group), :html => {:method => :post}) do |f| %>
+ <%= form_for(@group, :remote => true, :url => group_users_path(@group),
+ :html => {:method => :post}) do |f| %>
<%=l(:label_user_new)%>
<%= label_tag "user_search", l(:label_user_search) %><%= text_field_tag 'user_search', nil %>
- <%= observe_field(:user_search,
- :frequency => 0.5,
- :update => :users,
- :url => autocomplete_for_user_group_path(@group),
- :method => :get,
- :with => 'q')
- %>
+ <%= javascript_tag "observeSearchfield('user_search', 'users', '#{ escape_javascript autocomplete_for_user_group_path(@group) }')" %>
<%= principals_check_box_tags 'user_ids[]', users %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/add_users.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/groups/add_users.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,4 @@
+$('#tab-content-users').html('<%= escape_javascript(render :partial => 'groups/users') %>');
+<% @users.each do |user| %>
+ $('#user-<%= user.id %>').effect("highlight");
+<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/destroy_membership.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/groups/destroy_membership.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,1 @@
+$('#tab-content-memberships').html('<%= escape_javascript(render :partial => 'groups/memberships') %>');
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/edit_membership.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/groups/edit_membership.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,6 @@
+<% if @membership.valid? %>
+ $('#tab-content-memberships').html('<%= escape_javascript(render :partial => 'groups/memberships') %>');
+ $('#member-<%= @membership.id %>').effect("highlight");
+<% else %>
+ alert('<%= raw(escape_javascript(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', ')))) %>');
+<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/index.api.rsb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/groups/index.api.rsb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,10 @@
+api.array :groups do
+ @groups.each do |group|
+ api.group do
+ api.id group.id
+ api.name group.lastname
+
+ render_api_custom_values group.visible_custom_field_values, api
+ end
+ end
+end
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/index.html.erb
--- a/app/views/groups/index.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/groups/index.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -16,7 +16,7 @@
<%= link_to h(group), edit_group_path(group) %>
<%= group.users.size %>
- <%= link_to l(:button_delete), group, :confirm => l(:text_are_you_sure), :method => :delete, :class => 'icon icon-del' %>
+ <%= delete_link group %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/new.html.erb
--- a/app/views/groups/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/groups/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<%= link_to l(:label_group_plural), groups_path %> » <%= l(:label_group_new) %>
-<% labelled_form_for @group do |f| %>
+<%= labelled_form_for @group do |f| %>
<%= render :partial => 'form', :locals => { :f => f } %>
<%= f.submit l(:button_create) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/remove_user.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/groups/remove_user.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,1 @@
+$('#tab-content-users').html('<%= escape_javascript(render :partial => 'groups/users') %>');
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/groups/show.api.rsb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/groups/show.api.rsb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,30 @@
+api.group do
+ api.id @group.id
+ api.name @group.lastname
+
+ render_api_custom_values @group.visible_custom_field_values, api
+
+ api.array :users do
+ @group.users.each do |user|
+ api.user :id => user.id, :name => user.name
+ end
+ end if include_in_api_response?('users')
+
+ api.array :memberships do
+ @group.memberships.each do |membership|
+ api.membership do
+ api.id membership.id
+ api.project :id => membership.project.id, :name => membership.project.name
+ api.array :roles do
+ membership.member_roles.each do |member_role|
+ if member_role.role
+ attrs = {:id => member_role.role.id, :name => member_role.role.name}
+ attrs.merge!(:inherited => true) if member_role.inherited_from.present?
+ api.role attrs
+ end
+ end
+ end
+ end if membership.project
+ end
+ end if include_in_api_response?('memberships')
+end
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_categories/_form.html.erb
--- a/app/views/issue_categories/_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issue_categories/_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<%= error_messages_for 'category' %>
-
+
<%= f.text_field :name, :size => 30, :required => true %>
<%= f.select :assigned_to_id, principals_options_for_select(@project.assignable_users, @category.assigned_to), :include_blank => true %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_categories/_new_modal.html.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/issue_categories/_new_modal.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,9 @@
+
<%=l(:label_issue_category_new)%>
+
+<%= labelled_form_for @category, :as => 'issue_category', :url => project_issue_categories_path(@project), :remote => true do |f| %>
+<%= render :partial => 'issue_categories/form', :locals => { :f => f } %>
+
+ <%= submit_tag l(:button_create), :name => nil %>
+ <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
+
+<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_categories/create.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/issue_categories/create.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,3 @@
+hideModal();
+<% select = content_tag('select', content_tag('option') + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]') %>
+$('#issue_category_id').replaceWith('<%= escape_javascript(select) %>');
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_categories/destroy.html.erb
--- a/app/views/issue_categories/destroy.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issue_categories/destroy.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<%=l(:label_issue_category)%>: <%=h @category.name %>
-<% form_tag(issue_category_path(@category), :method => :delete) do %>
+<%= form_tag(issue_category_path(@category), :method => :delete) do %>
<%= l(:text_issue_category_destroy_question, @issue_count) %>
<%= radio_button_tag 'todo', 'nullify', true %> <%= l(:text_issue_category_destroy_assignments) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_categories/edit.html.erb
--- a/app/views/issue_categories/edit.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issue_categories/edit.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,7 @@
<%=l(:label_issue_category)%>
-<% labelled_tabular_form_for :issue_category, @category, :url => issue_category_path(@category), :html => {:method => :put} do |f| %>
+<%= labelled_form_for @category, :as => :issue_category,
+ :url => issue_category_path(@category), :html => {:method => :put} do |f| %>
<%= render :partial => 'issue_categories/form', :locals => { :f => f } %>
<%= submit_tag l(:button_save) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_categories/new.html.erb
--- a/app/views/issue_categories/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issue_categories/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,7 @@
<%=l(:label_issue_category_new)%>
-<% labelled_tabular_form_for :issue_category, @category, :url => project_issue_categories_path(@project) do |f| %>
+<%= labelled_form_for @category, :as => :issue_category,
+ :url => project_issue_categories_path(@project) do |f| %>
<%= render :partial => 'issue_categories/form', :locals => { :f => f } %>
<%= submit_tag l(:button_create) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_categories/new.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/issue_categories/new.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,2 @@
+$('#ajax-modal').html('<%= escape_javascript(render :partial => 'issue_categories/new_modal') %>');
+showModal('ajax-modal', '600px');
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_moves/new.html.erb
--- a/app/views/issue_moves/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-
<%= @copy ? l(:button_copy) : l(:button_move) %>
-
-
-<% @issues.each do |issue| -%>
- <%= link_to_issue issue %>
-<% end -%>
-
-
-<% form_tag({:action => 'create'}, :id => 'move_form') do %>
-<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>
-
-
-
-<%= l(:label_change_properties) %>
-
-
-
<%=l(:field_project)%>:
-<%= select_tag "new_project_id",
- project_tree_options_for_select(@allowed_projects, :selected => @target_project),
- :onchange => remote_function(:url => { :action => 'new' },
- :method => :get,
- :update => 'content',
- :with => "Form.serialize('move_form')") %>
-
-
<%=l(:field_tracker)%>:
-<%= select_tag "new_tracker_id", "#{l(:label_no_change_option)} " + options_from_collection_for_select(@trackers, "id", "name") %>
-
-
- <%= l(:field_status) %>
- <%= select_tag('status_id', "#{l(:label_no_change_option)} " + options_from_collection_for_select(@available_statuses, :id, :name)) %>
-
-
-
- <%= l(:field_priority) %>
- <%= select_tag('priority_id', "#{l(:label_no_change_option)} " + options_from_collection_for_select(IssuePriority.active, :id, :name)) %>
-
-
-
- <%= l(:field_assigned_to) %>
- <%= select_tag('assigned_to_id', content_tag('option', l(:label_no_change_option), :value => '') +
- content_tag('option', l(:label_nobody), :value => 'none') +
- principals_options_for_select(@target_project.assignable_users)) %>
-
-
-
-
-
- <%= l(:field_start_date) %>
- <%= text_field_tag 'start_date', '', :size => 10 %><%= calendar_for('start_date') %>
-
-
-
- <%= l(:field_due_date) %>
- <%= text_field_tag 'due_date', '', :size => 10 %><%= calendar_for('due_date') %>
-
-
-
-
-
-
<%= l(:field_notes) %>
-<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
-<%= wikitoolbar_for 'notes' %>
-
-
-<%= call_hook(:view_issues_move_bottom, :issues => @issues, :target_project => @target_project, :copy => !!@copy) %>
-
-
-<% if @copy %>
- <%= hidden_field_tag("copy_options[copy]", "1") %>
- <%= submit_tag l(:button_copy) %>
- <%= submit_tag l(:button_copy_and_follow), :name => 'follow' %>
-<% else %>
- <%= submit_tag l(:button_move) %>
- <%= submit_tag l(:button_move_and_follow), :name => 'follow' %>
-<% end %>
-<% end %>
-<% content_for :header_tags do %>
- <%= robot_exclusion_tag %>
-<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_relations/_form.html.erb
--- a/app/views/issue_relations/_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issue_relations/_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -2,13 +2,13 @@
<%= f.select :relation_type, collection_for_relation_type_select, {}, :onchange => "setPredecessorFieldsVisibility();" %>
<%= l(:label_issue) %> #<%= f.text_field :issue_to_id, :size => 10 %>
-
-<%= javascript_tag "observeRelatedIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %>
<%= l(:field_delay) %>: <%= f.text_field :delay, :size => 3 %> <%= l(:label_day_plural) %>
<%= submit_tag l(:button_add) %>
-<%= toggle_link l(:button_cancel), 'new-relation-form'%>
+<%= link_to_function l(:button_cancel), '$("#new-relation-form").hide();'%>
+<%= javascript_tag "observeAutocompleteField('relation_issue_to_id', '#{escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (Setting.cross_project_issue_relations? ? 'all' : nil))}')" %>
+
<%= javascript_tag "setPredecessorFieldsVisibility();" %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_relations/create.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/issue_relations/create.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,6 @@
+$('#relations').html('<%= escape_javascript(render :partial => 'issues/relations') %>');
+<% if @relation.errors.empty? %>
+ $('#relation_delay').val('');
+ $('#relation_issue_to_id').val('');
+ $('#relation_issue_to_id').focus();
+<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_relations/destroy.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/issue_relations/destroy.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,1 @@
+$('#relation-<%= @relation.id %>').remove();
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_statuses/edit.html.erb
--- a/app/views/issue_statuses/edit.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issue_statuses/edit.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<%= link_to l(:label_issue_status_plural), issue_statuses_path %> » <%=h @issue_status %>
-<% form_for @issue_status, :builder => TabularFormBuilder do |f| %>
+<%= labelled_form_for @issue_status do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= submit_tag l(:button_save) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_statuses/index.html.erb
--- a/app/views/issue_statuses/index.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issue_statuses/index.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<%= link_to l(:label_issue_status_new), new_issue_status_path, :class => 'icon icon-add' %>
-<%= link_to(l(:label_update_issue_done_ratios), update_issue_done_ratio_issue_statuses_path, :class => 'icon icon-multiple', :method => 'post', :confirm => l(:text_are_you_sure)) if Issue.use_status_for_done_ratio? %>
+<%= link_to(l(:label_update_issue_done_ratios), update_issue_done_ratio_issue_statuses_path, :class => 'icon icon-multiple', :method => 'post', :data => {:confirm => l(:text_are_you_sure)}) if Issue.use_status_for_done_ratio? %>
<%=l(:label_issue_status_plural)%>
@@ -27,10 +27,7 @@
<%= checked_image status.is_closed? %>
<%= reorder_links('issue_status', {:action => 'update', :id => status}, :put) %>
- <%= link_to(l(:button_delete), issue_status_path(status),
- :method => :delete,
- :confirm => l(:text_are_you_sure),
- :class => 'icon icon-del') %>
+ <%= delete_link issue_status_path(status) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issue_statuses/new.html.erb
--- a/app/views/issue_statuses/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issue_statuses/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<%= link_to l(:label_issue_status_plural), issue_statuses_path %> » <%=l(:label_issue_status_new)%>
-<% form_for @issue_status, :builder => TabularFormBuilder do |f| %>
+<%= labelled_form_for @issue_status do |f| %>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= submit_tag l(:button_create) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_action_menu.html.erb
--- a/app/views/issues/_action_menu.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/_action_menu.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,9 +1,7 @@
-<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
-<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %>
+<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "issue_notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
+<%= link_to l(:button_log_time), new_issue_time_entry_path(@issue), :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project) %>
<%= watcher_tag(@issue, User.current) %>
-<%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %>
-<%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %>
-<%= link_to_if_authorized l(:button_move), {:controller => 'issue_moves', :action => 'new', :id => @issue}, :class => 'icon icon-move' %>
-<%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => issues_destroy_confirmation_message(@issue), :method => :post, :class => 'icon icon-del' %>
+<%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, :class => 'icon icon-copy' %>
+<%= link_to l(:button_delete), issue_path(@issue), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_attributes.html.erb
--- a/app/views/issues/_attributes.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/_attributes.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,50 +1,73 @@
-<% fields_for :issue, @issue, :builder => TabularFormBuilder do |f| %>
+<%= labelled_fields_for :issue, @issue do |f| %>
+
-<% if @issue.new_record? || @allowed_statuses.any? %>
-
<%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>
+<% if @issue.safe_attribute?('status_id') && @allowed_statuses.present? %>
+
<%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true},
+ :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %>
+
<% else %>
<%= l(:field_status) %> <%= h(@issue.status.name) %>
<% end %>
+<% if @issue.safe_attribute? 'priority_id' %>
<%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), {:required => true}, :disabled => !@issue.leaf? %>
-
<%= f.select :assigned_to_id, principals_options_for_select(@issue.assignable_users, @issue.assigned_to), :include_blank => true %>
-<% unless @project.issue_categories.empty? %>
-
<%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
-<%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'),
- l(:label_issue_category_new),
- 'issue_category[name]',
- {:controller => 'issue_categories', :action => 'create', :project_id => @project},
- :title => l(:label_issue_category_new),
- :tabindex => 199) if authorize_for('issue_categories', 'new') %>
<% end %>
-<% unless @issue.assignable_versions.empty? %>
-
<%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true %>
-<%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'),
- l(:label_version_new),
- 'version[name]',
- {:controller => 'versions', :action => 'create', :project_id => @project},
- :title => l(:label_version_new),
- :tabindex => 200) if authorize_for('versions', 'new') %>
+
+<% if @issue.safe_attribute? 'assigned_to_id' %>
+
<%= f.select :assigned_to_id, principals_options_for_select(@issue.assignable_users, @issue.assigned_to), :include_blank => true, :required => @issue.required_attribute?('assigned_to_id') %>
+<% end %>
+
+<% if @issue.safe_attribute?('category_id') && @issue.project.issue_categories.any? %>
+
<%= f.select :category_id, (@issue.project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true, :required => @issue.required_attribute?('category_id') %>
+<%= link_to(image_tag('add.png', :style => 'vertical-align: middle;'),
+ new_project_issue_category_path(@issue.project),
+ :remote => true,
+ :method => 'get',
+ :title => l(:label_issue_category_new),
+ :tabindex => 200) if User.current.allowed_to?(:manage_categories, @issue.project) %>
+<% end %>
+
+<% if @issue.safe_attribute?('fixed_version_id') && @issue.assignable_versions.any? %>
+
<%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true, :required => @issue.required_attribute?('fixed_version_id') %>
+<%= link_to(image_tag('add.png', :style => 'vertical-align: middle;'),
+ new_project_version_path(@issue.project),
+ :remote => true,
+ :method => 'get',
+ :title => l(:label_version_new),
+ :tabindex => 200) if User.current.allowed_to?(:manage_versions, @issue.project) %>
<% end %>
-<% if User.current.allowed_to?(:manage_subtasks, @project) %>
-
<%= f.text_field :parent_issue_id, :size => 10 %>
-
-<%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %>
+<% if @issue.safe_attribute? 'parent_issue_id' %>
+
<%= f.text_field :parent_issue_id, :size => 10, :required => @issue.required_attribute?('parent_issue_id') %>
+<%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript auto_complete_issues_path}')" %>
<% end %>
-
<%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_start_date') if @issue.leaf? %>
-
<%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf? %><%= calendar_for('issue_due_date') if @issue.leaf? %>
-
<%= f.text_field :estimated_hours, :size => 3, :disabled => !@issue.leaf? %> <%= l(:field_hours) %>
-<% if @issue.leaf? && Issue.use_field_for_done_ratio? %>
-
<%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>
+
+<% if @issue.safe_attribute? 'start_date' %>
+
<%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('start_date') %><%= calendar_for('issue_start_date') if @issue.leaf? %>
+<% end %>
+
+<% if @issue.safe_attribute? 'due_date' %>
+
<%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('due_date') %><%= calendar_for('issue_due_date') if @issue.leaf? %>
+<% end %>
+
+<% if @issue.safe_attribute? 'estimated_hours' %>
+
<%= f.text_field :estimated_hours, :size => 3, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('estimated_hours') %> <%= l(:field_hours) %>
+<% end %>
+
+<% if @issue.safe_attribute?('done_ratio') && @issue.leaf? && Issue.use_field_for_done_ratio? %>
+
<%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :required => @issue.required_attribute?('done_ratio') %>
<% end %>
+
-
+<% if @issue.safe_attribute? 'custom_field_values' %>
<%= render :partial => 'issues/form_custom_fields' %>
+<% end %>
<% end %>
+
+<% include_calendar_headers_tags %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_changesets.html.erb
--- a/app/views/issues/_changesets.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/_changesets.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,6 +1,6 @@
<% changesets.each do |changeset| %>
-
<%= link_to_revision(changeset, changeset.project,
+
<%= link_to_revision(changeset, changeset.repository,
:text => "#{l(:label_revision)} #{changeset.format_identifier}") %>
<%= authoring(changeset.committed_on, changeset.author) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_conflict.html.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/issues/_conflict.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,26 @@
+
+ <%= l(:notice_issue_update_conflict) %>
+ <% if @conflict_journals.present? %>
+
+ <% @conflict_journals.sort_by(&:id).each do |journal| %>
+
<%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>
+ <% if journal.details.any? %>
+
+ <% details_to_strings(journal.details).each do |string| %>
+ <%= string %>
+ <% end %>
+
+ <% end %>
+ <%= textilizable(journal, :notes) unless journal.notes.blank? %>
+ <% end %>
+
+ <% end %>
+
+
+ <%= radio_button_tag 'conflict_resolution', 'overwrite' %> <%= l(:text_issue_conflict_resolution_overwrite) %>
+ <% if @issue.notes.present? %>
+ <%= radio_button_tag 'conflict_resolution', 'add_notes' %> <%= l(:text_issue_conflict_resolution_add_notes) %>
+ <% end %>
+ <%= radio_button_tag 'conflict_resolution', 'cancel' %> <%= l(:text_issue_conflict_resolution_cancel, :link => link_to_issue(@issue, :subject => false)).html_safe %>
+
+
<%= submit_tag l(:button_submit) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_edit.html.erb
--- a/app/views/issues/_edit.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/_edit.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,23 +1,17 @@
-<% labelled_tabular_form_for :issue, @issue,
- :url => {:action => 'update', :id => @issue},
- :html => {:id => 'issue-form',
- :class => nil,
- :method => :put,
- :multipart => true} do |f| %>
+<%= labelled_form_for @issue, :html => {:id => 'issue-form', :multipart => true} do |f| %>
<%= error_messages_for 'issue', 'time_entry' %>
+ <%= render :partial => 'conflict' if @conflict %>
<% if @edit_allowed || !@allowed_statuses.empty? %>
-
<%= l(:label_change_properties) %>
- <% if !@issue.new_record? && !@issue.errors.any? && @edit_allowed %>
- (<%= link_to l(:label_more), {}, :onclick => 'Effect.toggle("issue_descr_fields", "appear", {duration:0.3}); return false;' %>)
- <% end %>
-
- <%= render :partial => (@edit_allowed ? 'form' : 'form_update'), :locals => {:f => f} %>
+ <%= l(:label_change_properties) %>
+
+ <%= render :partial => 'form', :locals => {:f => f} %>
+
<% end %>
<% if User.current.allowed_to?(:log_time, @project) %>
<%= l(:button_log_time) %>
- <% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %>
+ <%= labelled_fields_for :time_entry, @time_entry do |time_entry| %>
<%= time_entry.text_field :hours, :size => 6, :label => :label_spent_time %> <%= l(:field_hours) %>
@@ -33,23 +27,25 @@
<% end %>
<%= l(:field_notes) %>
- <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
- <%= wikitoolbar_for 'notes' %>
+ <%= f.text_area :notes, :cols => 60, :rows => 10, :class => 'wiki-edit', :no_label => true %>
+ <%= wikitoolbar_for 'issue_notes' %>
+
+ <% if @issue.safe_attribute? 'private_notes' %>
+ <%= f.check_box :private_notes, :no_label => true %> <%= l(:field_private_notes) %>
+ <% end %>
+
<%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %>
+
- <%=l(:label_attachment_plural)%> <%= render :partial => 'attachments/form' %>
+ <%= l(:label_attachment_plural) %>
+ <%= render :partial => 'attachments/form', :locals => {:container => @issue} %>
<%= f.hidden_field :lock_version %>
+ <%= hidden_field_tag 'last_journal_id', params[:last_journal_id] || @issue.last_journal_id %>
<%= submit_tag l(:button_submit) %>
- <%= link_to_remote l(:label_preview),
- { :url => preview_issue_path(:project_id => @project, :id => @issue),
- :method => 'post',
- :update => 'preview',
- :with => 'Form.serialize("issue-form")',
- :complete => "Element.scrollTo('preview')"
- }, :accesskey => accesskey(:preview) %>
+ <%= preview_link preview_edit_issue_path(:project_id => @project, :id => @issue), 'issue-form' %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_form.html.erb
--- a/app/views/issues/_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,40 +1,45 @@
+<%= labelled_fields_for :issue, @issue do |f| %>
<%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %>
-
>
-<% if @issue.safe_attribute_names.include?('is_private') %>
+<% if @issue.safe_attribute? 'is_private' %>
- <%= f.check_box :is_private, :no_label => true %> <%= l(:field_is_private) %>
+ <%= f.check_box :is_private, :no_label => true %><%= l(:field_is_private) %>
<% end %>
-
<%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %>
-<%= observe_field :issue_tracker_id, :url => { :action => :new, :project_id => @project, :id => @issue },
- :update => :attributes,
- :with => "Form.serialize('issue-form')" %>
+<% if @issue.safe_attribute? 'project_id' %>
+
<%= f.select :project_id, project_tree_options_for_select(@issue.allowed_target_projects, :selected => @issue.project), {:required => true},
+ :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %>
+<% end %>
+
+<% if @issue.safe_attribute? 'tracker_id' %>
+
<%= f.select :tracker_id, @issue.project.trackers.collect {|t| [t.name, t.id]}, {:required => true},
+ :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %>
+<% end %>
+
+<% if @issue.safe_attribute? 'subject' %>
<%= f.text_field :subject, :size => 80, :required => true %>
-
<%= f.text_area :description,
+<% end %>
+
+<% if @issue.safe_attribute? 'description' %>
+
+ <%= f.label_for_field :description, :required => @issue.required_attribute?('description') %>
+ <%= link_to_function image_tag('edit.png'), '$(this).hide(); $("#issue_description_and_toolbar").show()' unless @issue.new_record? %>
+ <%= content_tag 'span', :id => "issue_description_and_toolbar", :style => (@issue.new_record? ? nil : 'display:none') do %>
+ <%= f.text_area :description,
:cols => 60,
:rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min),
:accesskey => accesskey(:edit),
- :class => 'wiki-edit' %>
-
+ :class => 'wiki-edit',
+ :no_label => true %>
+ <% end %>
+
+<%= wikitoolbar_for 'issue_description' %>
+<% end %>
<%= render :partial => 'issues/attributes' %>
-<% if @issue.new_record? %>
-
<%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form' %>
+<%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %>
<% end %>
-
-<% if @issue.new_record? && User.current.allowed_to?(:add_issue_watchers, @project) -%>
-
<%= l(:label_issue_watchers) %>
-<% @issue.project.users.sort.each do |user| -%>
-<%= check_box_tag 'issue[watcher_user_ids][]', user.id, @issue.watched_by?(user) %> <%=h user %>
-<% end -%>
-
-<% end %>
-
-<%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %>
-
-<%= wikitoolbar_for 'issue_description' %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_form_custom_fields.html.erb
--- a/app/views/issues/_form_custom_fields.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/_form_custom_fields.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,12 +1,13 @@
+
<% i = 0 %>
<% split_on = (@issue.custom_field_values.size / 2.0).ceil - 1 %>
-<% @issue.custom_field_values.each do |value| %>
-
<%= custom_field_tag_with_label :issue, value %>
+<% @issue.editable_custom_field_values.each do |value| %>
+
<%= custom_field_tag_with_label :issue, value, :required => @issue.required_attribute?(value.custom_field_id) %>
<% if i == split_on -%>
<% end -%>
<% i += 1 -%>
<% end -%>
-
+
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_form_update.html.erb
--- a/app/views/issues/_form_update.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-
-
-
<%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>
-
<%= f.select :assigned_to_id, principals_options_for_select(@issue.assignable_users, @issue.assigned_to), :include_blank => true %>
-
-
-<% if Issue.use_field_for_done_ratio? %>
-
<%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>
-<% end %>
-<% unless @issue.assignable_versions.empty? %>
-
<%= f.select :fixed_version_id, (@issue.assignable_versions.collect {|v| [v.name, v.id]}), :include_blank => true %>
-<% end %>
-
-
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_history.html.erb
--- a/app/views/issues/_history.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/_history.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,19 +1,20 @@
<% reply_links = authorize_for('issues', 'edit') -%>
<% for journal in journals %>
-
<%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %>
+
+
<%= link_to "##{journal.indice}", {:anchor => "note-#{journal.indice}"}, :class => "journal-link" %>
<%= avatar(journal.user, :size => "24") %>
- <%= content_tag('a', '', :name => "note-#{journal.indice}")%>
<%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>
<% if journal.details.any? %>
- <% for detail in journal.details %>
- <%= show_detail(detail) %>
+ <% details_to_strings(journal.details).each do |string| %>
+ <%= string %>
<% end %>
<% end %>
<%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %>
+
<%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/_list.html.erb
--- a/app/views/issues/_list.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/_list.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,35 +1,47 @@
-<% form_tag({}) do -%>
-<%= hidden_field_tag 'back_url', url_for(params) %>
+<%= form_tag({}) do -%>
+<%= hidden_field_tag 'back_url', url_for(params), :id => nil %>
@@ -38,7 +47,9 @@
<%= link_to_function l(:button_apply), 'submit_query_form("query_form")', :class => 'icon icon-checked' %>
<%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %>
<% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %>
- <%= link_to_function l(:button_save), "$('query_form').action='#{ @project ? new_project_query_path : new_query_path }'; submit_query_form('query_form')", :class => 'icon icon-save' %>
+ <%= link_to_function l(:button_save),
+ "$('#query_form').attr('action', '#{ @project ? new_project_query_path(@project) : new_query_path }'); submit_query_form('query_form')",
+ :class => 'icon icon-save' %>
<% end %>
<% end %>
@@ -60,13 +71,13 @@
<%= l(:label_export_options, :export_format => 'CSV') %>
- <% form_tag(params.merge({:format => 'csv',:page=>nil}), :method => :get, :id => 'csv-export-form') do %>
+ <%= form_tag(params.merge({:format => 'csv',:page=>nil}), :method => :get, :id => 'csv-export-form') do %>
<%= radio_button_tag 'columns', '', true %> <%= l(:description_selected_columns) %>
<%= radio_button_tag 'columns', 'all' %> <%= l(:description_all_columns) %>
- <%= check_box_tag 'description', '1' %> <%= l(:field_description) %>
+ <%= check_box_tag 'description', '1', @query.has_column?(:description) %> <%= l(:field_description) %>
<%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %>
@@ -83,8 +94,15 @@
<% end %>
<% content_for :header_tags do %>
- <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %>
- <%= auto_discovery_link_tag(:atom, {:controller => 'journals', :action => 'index', :query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_changes_details)) %>
+ <%= auto_discovery_link_tag(:atom,
+ {:query_id => @query, :format => 'atom',
+ :page => nil, :key => User.current.rss_key},
+ :title => l(:label_issue_plural)) %>
+ <%= auto_discovery_link_tag(:atom,
+ {:controller => 'journals', :action => 'index',
+ :query_id => @query, :format => 'atom',
+ :page => nil, :key => User.current.rss_key},
+ :title => l(:label_changes_details)) %>
<% end %>
<%= context_menu issues_context_menu_path %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/new.html.erb
--- a/app/views/issues/new.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/new.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,27 +1,55 @@
<%=l(:label_issue_new)%>
-<% labelled_tabular_form_for :issue, @issue, :url => {:controller => 'issues', :action => 'create', :project_id => @project},
- :html => {:multipart => true, :id => 'issue-form', :class => 'tabular new-issue-form'} do |f| %>
- <%= error_messages_for 'issue' %>
-
+<%= call_hook(:view_issues_new_top, {:issue => @issue}) %>
+
+<%= labelled_form_for @issue, :url => project_issues_path(@project),
+ :html => {:id => 'issue-form', :multipart => true} do |f| %>
+ <%= error_messages_for 'issue' %>
+ <%= hidden_field_tag 'copy_from', params[:copy_from] if params[:copy_from] %>
+
+
<%= render :partial => 'issues/form', :locals => {:f => f} %>
- <%= submit_tag l(:button_create) %>
- <%= submit_tag l(:button_create_and_continue), :name => 'continue' %>
- <%= link_to_remote l(:label_preview),
- { :url => preview_issue_path(:project_id => @project),
- :method => 'post',
- :update => 'preview',
- :with => "Form.serialize('issue-form')",
- :complete => "Element.scrollTo('preview')"
- }, :accesskey => accesskey(:preview) %>
- <%= javascript_tag "Form.Element.focus('issue_subject');" %>
+ <% if @copy_from && @copy_from.attachments.any? %>
+
+ <%= l(:label_copy_attachments) %>
+ <%= check_box_tag 'copy_attachments', '1', @copy_attachments %>
+
+ <% end %>
+ <% if @copy_from && !@copy_from.leaf? %>
+
+ <%= l(:label_copy_subtasks) %>
+ <%= check_box_tag 'copy_subtasks', '1', @copy_subtasks %>
+
+ <% end %>
+
+
<%= l(:label_attachment_plural) %> <%= render :partial => 'attachments/form', :locals => {:container => @issue} %>
+
+ <% if @issue.safe_attribute? 'watcher_user_ids' -%>
+
<%= l(:label_issue_watchers) %>
+
+ <%= watchers_checkboxes(@issue, @available_watchers) %>
+
+
+ <%= link_to l(:label_search_for_watchers),
+ {:controller => 'watchers', :action => 'new', :project_id => @issue.project},
+ :remote => true,
+ :method => 'get' %>
+
+
+ <% end %>
+
+
+ <%= submit_tag l(:button_create) %>
+ <%= submit_tag l(:button_create_and_continue), :name => 'continue' %>
+ <%= preview_link preview_new_issue_path(:project_id => @project), 'issue-form' %>
+
+ <%= javascript_tag "$('#issue_subject').focus();" %>
<% end %>
<% content_for :header_tags do %>
- <%= stylesheet_link_tag 'scm' %>
<%= robot_exclusion_tag %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/show.api.rsb
--- a/app/views/issues/show.api.rsb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/show.api.rsb Mon Jan 07 12:01:42 2013 +0000
@@ -48,7 +48,7 @@
end if include_in_api_response?('changesets') && User.current.allowed_to?(:view_changesets, @project)
api.array :journals do
- @issue.journals.each do |journal|
+ @journals.each do |journal|
api.journal :id => journal.id do
api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil?
api.notes journal.notes
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/issues/show.html.erb
--- a/app/views/issues/show.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/issues/show.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -3,7 +3,23 @@
<%= issue_heading(@issue) %>
- <%= avatar(@issue.author, :size => "50") %>
+ <% if @prev_issue_id || @next_issue_id %>
+
+ <%= link_to_if @prev_issue_id,
+ "\xc2\xab #{l(:label_previous)}",
+ (@prev_issue_id ? issue_path(@prev_issue_id) : nil),
+ :title => "##{@prev_issue_id}" %> |
+ <% if @issue_position && @issue_count %>
+ <%= l(:label_item_position, :position => @issue_position, :count => @issue_count) %> |
+ <% end %>
+ <%= link_to_if @next_issue_id,
+ "#{l(:label_next)} \xc2\xbb",
+ (@next_issue_id ? issue_path(@next_issue_id) : nil),
+ :title => "##{@next_issue_id}" %>
+
+ <% end %>
+
+ <%= avatar(@issue.author, :size => "50") %>
<%= render_issue_subject_with_tree(@issue) %>
@@ -11,36 +27,43 @@
<%= authoring @issue.created_on, @issue.author %>.
<% if @issue.created_on != @issue.updated_on %>
- <%= l(:label_updated_time, time_tag(@issue.updated_on)) %>.
+ <%= l(:label_updated_time, time_tag(@issue.updated_on)).html_safe %>.
<% end %>
-
- <%=l(:field_status)%>: <%= h(@issue.status.name) %>
- <%=l(:field_start_date)%>: <%= format_date(@issue.start_date) %>
-
-
- <%=l(:field_priority)%>: <%= h(@issue.priority.name) %>
- <%=l(:field_due_date)%>: <%= format_date(@issue.due_date) %>
-
-
- <%=l(:field_assigned_to)%>: <%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %>
- <%=l(:field_done_ratio)%>: <%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %>
-
-
- <%=l(:field_category)%>: <%=h(@issue.category ? @issue.category.name : "-") %>
- <% if User.current.allowed_to?(:view_time_entries, @project) %>
- <%=l(:label_spent_time)%>:
- <%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %>
- <% end %>
-
-
- <%=l(:field_fixed_version)%>: <%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %>
- <% if @issue.estimated_hours %>
- <%=l(:field_estimated_hours)%>: <%= l_hours(@issue.estimated_hours) %>
- <% end %>
-
+<%= issue_fields_rows do |rows|
+ rows.left l(:field_status), h(@issue.status.name), :class => 'status'
+ rows.left l(:field_priority), h(@issue.priority.name), :class => 'priority'
+
+ unless @issue.disabled_core_fields.include?('assigned_to_id')
+ rows.left l(:field_assigned_to), avatar(@issue.assigned_to, :size => "14").to_s.html_safe + (@issue.assigned_to ? link_to_user(@issue.assigned_to) : "-"), :class => 'assigned-to'
+ end
+ unless @issue.disabled_core_fields.include?('category_id')
+ rows.left l(:field_category), h(@issue.category ? @issue.category.name : "-"), :class => 'category'
+ end
+ unless @issue.disabled_core_fields.include?('fixed_version_id')
+ rows.left l(:field_fixed_version), (@issue.fixed_version ? link_to_version(@issue.fixed_version) : "-"), :class => 'fixed-version'
+ end
+
+ unless @issue.disabled_core_fields.include?('start_date')
+ rows.right l(:field_start_date), format_date(@issue.start_date), :class => 'start-date'
+ end
+ unless @issue.disabled_core_fields.include?('due_date')
+ rows.right l(:field_due_date), format_date(@issue.due_date), :class => 'due-date'
+ end
+ unless @issue.disabled_core_fields.include?('done_ratio')
+ rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress'
+ end
+ unless @issue.disabled_core_fields.include?('estimated_hours')
+ unless @issue.estimated_hours.nil?
+ rows.right l(:field_estimated_hours), l_hours(@issue.estimated_hours), :class => 'estimated-hours'
+ end
+ end
+ if User.current.allowed_to?(:view_time_entries, @project)
+ rows.right l(:label_spent_time), (@issue.total_spent_hours > 0 ? (link_to l_hours(@issue.total_spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-"), :class => 'spent-time'
+ end
+end %>
<%= render_custom_fields_rows(@issue) %>
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
@@ -48,16 +71,22 @@
<% if @issue.description? || @issue.attachments.any? -%>
<% if @issue.description? %>
+
- <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:controller => 'journals', :action => 'new', :id => @issue} }, :class => 'icon icon-comment') %>
+ <%= link_to l(:button_quote),
+ {:controller => 'journals', :action => 'new', :id => @issue},
+ :remote => true,
+ :method => 'post',
+ :class => 'icon icon-comment' if authorize_for('issues', 'edit') %>
<%=l(:field_description)%>
<%= textilizable @issue, :description, :attachments => @issue.attachments %>
+
<% end %>
-<%= link_to_attachments @issue %>
+<%= link_to_attachments @issue, :thumbnails => true %>
<% end -%>
<%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>
@@ -66,7 +95,7 @@
- <%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %>
+ <%= link_to_new_subtask(@issue) if User.current.allowed_to?(:manage_subtasks, @project) %>
<%=l(:label_subtask_plural)%>
<%= render_descendants_tree(@issue) unless @issue.leaf? %>
@@ -128,10 +157,6 @@
<% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %>
- <%= stylesheet_link_tag 'scm' %>
- <%= javascript_include_tag 'context_menu' %>
- <%= stylesheet_link_tag 'context_menu' %>
- <%= stylesheet_link_tag 'context_menu_rtl' if l(:direction) == 'rtl' %>
<% end %>
-
-<%= javascript_tag "new ContextMenu('#{issues_context_menu_path}')" %>
+
+<%= context_menu issues_context_menu_path %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/journals/_notes_form.html.erb
--- a/app/views/journals/_notes_form.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/journals/_notes_form.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,4 +1,6 @@
-<% form_remote_tag(:url => {}, :html => { :id => "journal-#{@journal.id}-form" }) do %>
+<%= form_tag({:controller => 'journals', :action => 'edit', :id => @journal},
+ :remote => true,
+ :id => "journal-#{@journal.id}-form") do %>
<%= label_tag "notes", l(:description_notes), :class => "hidden-for-sighted" %>
<%= text_area_tag :notes, @journal.notes,
:id => "journal_#{@journal.id}_notes",
@@ -6,16 +8,10 @@
:rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %>
<%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %>
<%= submit_tag l(:button_save) %>
- <%= link_to_remote l(:label_preview),
- { :url => preview_issue_path(:project_id => @project, :id => @journal.issue),
- :method => 'post',
- :update => "journal_#{@journal.id}_preview",
- :with => "Form.serialize('journal-#{@journal.id}-form')",
- :complete => "Element.scrollTo('journal_#{@journal.id}_preview')"
- }, :accesskey => accesskey(:preview) %>
- |
- <%= link_to l(:button_cancel), '#', :onclick => "Element.remove('journal-#{@journal.id}-form'); " +
- "Element.show('journal-#{@journal.id}-notes'); return false;" %>
+ <%= preview_link preview_edit_issue_path(:project_id => @project, :id => @journal.issue),
+ "journal-#{@journal.id}-form",
+ "journal_#{@journal.id}_preview" %> |
+ <%= link_to l(:button_cancel), '#', :onclick => "$('#journal-#{@journal.id}-form').remove(); $('#journal-#{@journal.id}-notes').show(); return false;" %>
<% end %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/journals/edit.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/journals/edit.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,8 @@
+$("#journal-<%= @journal.id %>-notes").hide();
+
+if ($("form#journal-<%= @journal.id %>-form").length > 0) {
+ // journal edit form already loaded
+ $("#journal-<%= @journal.id %>-form").show();
+} else {
+ $("#journal-<%= @journal.id %>-notes").after('<%= escape_javascript(render :partial => 'notes_form') %>');
+}
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/journals/edit.rjs
--- a/app/views/journals/edit.rjs Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-page.hide "journal-#{@journal.id}-notes"
-page.insert_html :after, "journal-#{@journal.id}-notes",
- :partial => 'notes_form'
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/journals/index.builder
--- a/app/views/journals/index.builder Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/journals/index.builder Mon Jan 07 12:01:42 2013 +0000
@@ -19,8 +19,8 @@
end
xml.content "type" => "html" do
xml.text! '
'
- change.details.each do |detail|
- xml.text! '' + show_detail(detail, false) + ' '
+ details_to_strings(change.details, false).each do |string|
+ xml.text! '' + string + ' '
end
xml.text! ' '
xml.text! textilizable(change, :notes, :only_path => false) unless change.notes.blank?
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/journals/new.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/journals/new.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,10 @@
+$('#issue_notes').val("<%= raw escape_javascript(@content) %>");
+<%
+ # when quoting a private journal, check the private checkbox
+ if @journal && @journal.private_notes?
+%>
+$('#issue_private_notes').attr('checked', true);
+<% end %>
+
+showAndScrollTo("update", "notes");
+$('#notes').scrollTop = $('#notes').scrollHeight - $('#notes').clientHeight;
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/journals/update.js.erb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/views/journals/update.js.erb Mon Jan 07 12:01:42 2013 +0000
@@ -0,0 +1,9 @@
+<% if @journal.frozen? %>
+ $("#change-<%= @journal.id %>").remove();
+<% else %>
+ $("#journal-<%= @journal.id %>-notes").replaceWith('<%= escape_javascript(render_notes(@journal.issue, @journal, :reply_links => authorize_for('issues', 'edit'))) %>');
+ $("#journal-<%= @journal.id %>-notes").show();
+ $("#journal-<%= @journal.id %>-form").remove();
+<% end %>
+
+<%= call_hook(:view_journals_update_js_bottom, { :journal => @journal }) %>
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/journals/update.rjs
--- a/app/views/journals/update.rjs Wed Jun 27 14:54:18 2012 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-if @journal.frozen?
- # journal was destroyed
- page.remove "change-#{@journal.id}"
-else
- page.replace "journal-#{@journal.id}-notes", render_notes(@journal.issue, @journal, :reply_links => authorize_for('issues', 'edit'))
- page.show "journal-#{@journal.id}-notes"
- page.remove "journal-#{@journal.id}-form"
-end
-
-call_hook(:view_journals_update_rjs_bottom, { :page => page, :journal => @journal })
diff -r 5f33065ddc4b -r 433d4f72a19b app/views/layouts/base.html.erb
--- a/app/views/layouts/base.html.erb Wed Jun 27 14:54:18 2012 +0100
+++ b/app/views/layouts/base.html.erb Mon Jan 07 12:01:42 2013 +0000
@@ -1,22 +1,16 @@
-
-
+
+
-
+
<%=h html_title %>
<%= csrf_meta_tag %>
<%= favicon %>
-<%= stylesheet_link_tag 'application', :media => 'all' %>
+<%= stylesheet_link_tag 'jquery/jquery-ui-1.8.21', 'application', :media => 'all' %>
<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %>
<%= javascript_heads %>
<%= heads_for_theme %>
-
<%= call_hook :view_layouts_base_html_head %>
<%= yield :header_tags -%>
@@ -24,21 +18,19 @@
+
<%= l(:label_loading) %>
+