How can I programmatically register a file with Redmine?

Sean Allred

I'd like to add a file to a Redmine server without going through the graphical interface. I'm making the files available to the Redmine server by a separate svn checkout process, so I just need to be able to add the files to Redmine's own database.

Ideally, I'd like a solution that could be run like this:

./redmine-register-file /path/to/my/file.ext "with optional description"

I believe the relevant part of the interface is found in redmine/apps/views/files/new.html.erb. It's accessed by index.html.erb, which has a small portion I believe is relevant:

<div class="contextual">
<%= link_to(l(:label_attachment_new), new_project_file_path(@project), :class => 'icon icon-add') if User.current.allowed_to?(:manage_files, @project) %>
</div>

Here is the complete contents of new.html.erb:

<h2><%=l(:label_attachment_new)%></h2>

<%= error_messages_for 'attachment' %>
<%= form_tag(project_files_path(@project), :multipart => true, :class => "tabular") do %>
<div class="box">

<% if @versions.any? %>
<p><label for="version_id"><%=l(:field_version)%></label>
<%= select_tag "version_id", content_tag('option', '') +
                             options_from_collection_for_select(@versions, "id", "name") %></p>
<% end %>

<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>
</div>
<%= submit_tag l(:button_add) %>
<% end %>

I don't know Ruby that well at all (anything beyond print name.reverse is beyond me), but I know that all of those colons indicate selectors. What information can I glean from the standard interface that will help me in my task, and what might a complete solution look like?


Closer to a solution:

Redmine uses a MySQL database to store its file registrations. The database is called redmine_production, and uses the following schema:

mysql> SHOW COLUMNS FROM redmine_production.attachments;
+----------------+--------------+------+-----+---------+----------------+
| Field          | Type         | Null | Key | Default | Extra          |
+----------------+--------------+------+-----+---------+----------------+
| id             | int(11)      | NO   | PRI | NULL    | auto_increment |
| container_id   | int(11)      | YES  | MUL | NULL    |                |
| container_type | varchar(30)  | YES  |     | NULL    |                |
| filename       | varchar(255) | NO   |     |         |                |
| disk_filename  | varchar(255) | NO   |     |         |                |
| filesize       | int(11)      | NO   |     | 0       |                |
| content_type   | varchar(255) | YES  |     |         |                |
| digest         | varchar(40)  | NO   |     |         |                |
| downloads      | int(11)      | NO   |     | 0       |                |
| author_id      | int(11)      | NO   | MUL | 0       |                |
| created_on     | datetime     | YES  | MUL | NULL    |                |
| description    | varchar(255) | YES  |     | NULL    |                |
+----------------+--------------+------+-----+---------+----------------+
12 rows in set (0.00 sec)

Some more Ruby source

Perhaps this will be of use: attachment.rb

Sean Allred

For those who come by this by the Redmine thread I created: I tried to post the solution there as well, but the SPAM filter would not let me follow-up on the thread. It is probably because there was no intermediate response (*tear*).


It took a bit of time, but I figured it out. (I made a test instance of Redmine so as to not mess anything up with our production instance, so these values are default and should work for anybody trying to do this.)


A short synopsis of the process:

  1. Find the internal ID of the project you wish to add the files to.
  2. Determine file statistics.
  3. Insert file into database.

There is in fact no database validation going on, so even (2) is optional. As such, I won't go over how to get that information. (There are ample resources even on this site as to how to get this information.) The rest, however, requires a tiny bit of knowledge of how Redmine has its databases set up.


To start this, connect to your production MySQL database. (This is usually, if not always, redmine_production. You can list all MySQL databases with the command SHOW DATABASES;.)

Now, find the ID of your project you wish to add the file to. In the columns listing above, this will be inserted as container_id.

mysql> SELECT * FROM projects;
+----+----------------+-------------+----------+-----------+-----------+---------------------+---------------------+----------------+--------+------+------+
| id | name           | description | homepage | is_public | parent_id | created_on          | updated_on          | identifier     | status | lft  | rgt  |
+----+----------------+-------------+----------+-----------+-----------+---------------------+---------------------+----------------+--------+------+------+
|  1 | git-helloworld | NULL        |          |         1 |      NULL | 2012-01-01 13:00:00 | 2012-01-01 13:00:00 | git-helloworld |      1 |    1 |    2 |
|  2 | bzr-helloworld | NULL        |          |         1 |      NULL | 2012-01-01 13:00:00 | 2012-01-01 13:00:00 | bzr-helloworld |      1 |    1 |    2 |
|  3 | hg-helloworld  | NULL        |          |         1 |      NULL | 2012-01-01 13:00:00 | 2012-01-01 13:00:00 | hg-helloworld  |      1 |    1 |    2 |
|  4 | svn-helloworld | NULL        |          |         1 |      NULL | 2012-01-01 13:00:00 | 2012-01-01 13:00:00 | svn-helloworld |      1 |    1 |    2 |
+----+----------------+-------------+----------+-----------+-----------+---------------------+---------------------+----------------+--------+------+------+
4 rows in set (0.00 sec)

In this example, we want to add the files to git-helloworld, so our ID is 1. So, to add a file to the database, we will execute the SQL command:

INSERT INTO attachments (container_id, container_type,
                         filename, disk_filename, digest) VALUES (
       1, 'Project',
       'Some File Name', 'file-name-on-disk', '0123456789abcdef');

A few notes about these fields:

  • container_id: The ID of the project you wish to include the file in
  • container_type: The type of container this is; for this purpose, it is always Project
  • filename: The string to display as the file name
  • disk_filename: The actual path of the file, relative to /var/www/redmine/files/
  • digest: A string representing the MD5 checksum of the file.

Some not required, but recommended fields:

  • filesize: The size of the file as an integer. I assume this is meant to be in bytes or kilobytes, but I don't know if it matters.
  • author_id: A user to associate the file with. For my purposes, I'm going to use admin. Note that you can get a full list of Redmine users with SELECT * FROM users;.
  • description: A file description. (This is the same optional description used in the interface.)
  • content_type: I would assume this is a MIME content type.
  • created_on: The date this file was created on.

For the explicit types of all of these, refer to the columns listing in the original post.

Next, ensure that the path in disk_filename actually exists relative to your redmine/files/ directory. (Note this means that you can actually organize it!) You don't have to do this, but you will obviously get a 404 if the file isn't there.

After that, you should be good to go!

proof

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

How can I save multiple pages of the PDF version of an Acumatica report to a file programmatically?

分類Dev

How can I programmatically segue with tapping on an Image?

分類Dev

How can I programmatically cause a delay in Android?

分類Dev

How can I change ImageButton size programmatically?

分類Dev

Can I skip file validation when programmatically opening a workbook?

分類Dev

Can I skip file validation when programmatically opening a workbook?

分類Dev

How can I programmatically tell if a filename matches a shell glob pattern?

分類Dev

How can I enable or disable the GPS programmatically on Android?

分類Dev

How can I programmatically create a list of objects of the leaflet icon class?

分類Dev

MacOS: How can I activate fonts programmatically, systemwide?

分類Dev

How can i open default Files app with myapp folder programmatically?

分類Dev

How can I place a phone call programmatically from a Mac app?

分類Dev

How can I programmatically determine the time a Gmail label was applied to a message?

分類Dev

How can I add UIBarButtonItem to my navigation controller programmatically?

分類Dev

Can I register Orchard resources in an HtmlHelper?

分類Dev

Programmatically register a broadcast receiver

分類Dev

ASP.NET MVC How may I register a resource file in my view folder, to be used as @using

分類Dev

SQLCLR - How can I register referenced assemblies of my CLR assembly without setting TRUSTWORTHY ON?

分類Dev

How can I "register" a new help.txt document via .vimrc?

分類Dev

How can I view file header information?

分類Dev

How can I delete the current file in vim?

分類Dev

How can I save cursor to file .cur?

分類Dev

How can I define IQueryable in proto file

分類Dev

How can I save the last command to a file?

分類Dev

How can I display any file on browser

分類Dev

How can I write a collection of objects to file?

分類Dev

Can I programmatically set an objects property in iOS?

分類Dev

How can I open, edit and save an MS-Word document programmatically?

分類Dev

How can I write the text file content equal to file name?

Related 関連記事

  1. 1

    How can I save multiple pages of the PDF version of an Acumatica report to a file programmatically?

  2. 2

    How can I programmatically segue with tapping on an Image?

  3. 3

    How can I programmatically cause a delay in Android?

  4. 4

    How can I change ImageButton size programmatically?

  5. 5

    Can I skip file validation when programmatically opening a workbook?

  6. 6

    Can I skip file validation when programmatically opening a workbook?

  7. 7

    How can I programmatically tell if a filename matches a shell glob pattern?

  8. 8

    How can I enable or disable the GPS programmatically on Android?

  9. 9

    How can I programmatically create a list of objects of the leaflet icon class?

  10. 10

    MacOS: How can I activate fonts programmatically, systemwide?

  11. 11

    How can i open default Files app with myapp folder programmatically?

  12. 12

    How can I place a phone call programmatically from a Mac app?

  13. 13

    How can I programmatically determine the time a Gmail label was applied to a message?

  14. 14

    How can I add UIBarButtonItem to my navigation controller programmatically?

  15. 15

    Can I register Orchard resources in an HtmlHelper?

  16. 16

    Programmatically register a broadcast receiver

  17. 17

    ASP.NET MVC How may I register a resource file in my view folder, to be used as @using

  18. 18

    SQLCLR - How can I register referenced assemblies of my CLR assembly without setting TRUSTWORTHY ON?

  19. 19

    How can I "register" a new help.txt document via .vimrc?

  20. 20

    How can I view file header information?

  21. 21

    How can I delete the current file in vim?

  22. 22

    How can I save cursor to file .cur?

  23. 23

    How can I define IQueryable in proto file

  24. 24

    How can I save the last command to a file?

  25. 25

    How can I display any file on browser

  26. 26

    How can I write a collection of objects to file?

  27. 27

    Can I programmatically set an objects property in iOS?

  28. 28

    How can I open, edit and save an MS-Word document programmatically?

  29. 29

    How can I write the text file content equal to file name?

ホットタグ

アーカイブ