{"id":34713228,"url":"https://github.com/zh/redmine_extended_api","last_synced_at":"2026-05-24T01:33:37.514Z","repository":{"id":324664669,"uuid":"1098006404","full_name":"zh/redmine_extended_api","owner":"zh","description":"Adds missing REST API endpoints: custom fields CRUD, queries CRUD, time entries bulk operations (globally available)","archived":false,"fork":false,"pushed_at":"2025-11-17T06:20:30.000Z","size":21,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-24T01:33:36.744Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zh.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-17T06:12:13.000Z","updated_at":"2025-11-17T06:20:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/zh/redmine_extended_api","commit_stats":null,"previous_names":["zh/redmine_extended_api"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zh/redmine_extended_api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zh%2Fredmine_extended_api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zh%2Fredmine_extended_api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zh%2Fredmine_extended_api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zh%2Fredmine_extended_api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zh","download_url":"https://codeload.github.com/zh/redmine_extended_api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zh%2Fredmine_extended_api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33418547,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"ssl_error","status_checked_at":"2026-05-23T22:14:43.778Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-25T00:50:45.458Z","updated_at":"2026-05-24T01:33:37.491Z","avatar_url":"https://github.com/zh.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Redmine Extended API\n\nAdds missing REST API endpoints to Redmine 6.1.x (globally available):\n- **Custom Fields CRUD**: Full management of custom fields\n- **Queries CRUD**: Create, update, and delete queries (saved filters)\n- **Time Entries Bulk**: Create multiple time entries in one request\n\n## Requirements\n- Redmine 6.1.0 or higher\n\n## Installation\n\n```bash\ncd /path/to/redmine/plugins\ngit clone https://github.com/zh/redmine_extended_api.git\ncd /path/to/redmine\nbundle install\nbundle exec rake redmine:plugins:migrate RAILS_ENV=production\nsystemctl restart redmine\n```\n\n## API Endpoints\n\n### 1. Custom Fields CRUD\n\n**POST /custom_fields.json** - Create custom field\n**PUT /custom_fields/:id.json** - Update custom field\n**DELETE /custom_fields/:id.json** - Delete custom field\n\n**Requires**: Admin privileges\n\n**Create Example**:\n```bash\ncurl -X POST \\\n  -H \"X-Redmine-API-Key: ADMIN_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"custom_field\": {\n      \"type\": \"IssueCustomField\",\n      \"name\": \"Priority Level\",\n      \"field_format\": \"list\",\n      \"possible_values\": [\"Low\", \"Medium\", \"High\"],\n      \"is_required\": false,\n      \"is_for_all\": true\n    }\n  }' \\\n  https://redmine.example.com/custom_fields.json\n```\n\n**Update Example**:\n```bash\ncurl -X PUT \\\n  -H \"X-Redmine-API-Key\": ADMIN_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"custom_field\":{\"name\":\"Updated Name\",\"is_required\":true}}' \\\n  https://redmine.example.com/custom_fields/5.json\n```\n\n**Delete Example**:\n```bash\ncurl -X DELETE \\\n  -H \"X-Redmine-API-Key: ADMIN_KEY\" \\\n  https://redmine.example.com/custom_fields/5.json\n```\n\n### 2. Queries CRUD\n\n**POST /extended_api/queries.json** - Create query\n**PUT /extended_api/queries/:id.json** - Update query\n**DELETE /extended_api/queries/:id.json** - Delete query\n\n**Permissions**: Users can create/update/delete their own private queries. Users with `manage_public_queries` permission can manage public project queries. Only admins can manage global public queries.\n\n**Create Private Query Example**:\n```bash\ncurl -X POST \\\n  -H \"X-Redmine-API-Key: YOUR_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"query\": {\n      \"name\": \"Late Issues Before May\",\n      \"type\": \"IssueQuery\",\n      \"visibility\": 0,\n      \"filters\": {\n        \"due_date\": {\"operator\": \"\u003c=\", \"values\": [\"2025-05-01\"]},\n        \"status_id\": {\"operator\": \"o\"}\n      }\n    }\n  }' \\\n  https://redmine.example.com/extended_api/queries.json\n```\n\n**Create Public Project Query Example**:\n```bash\ncurl -X POST \\\n  -H \"X-Redmine-API-Key: YOUR_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"query\": {\n      \"name\": \"My Team Issues\",\n      \"type\": \"IssueQuery\",\n      \"project_id\": 5,\n      \"visibility\": 2,\n      \"filters\": {\n        \"assigned_to_id\": {\"operator\": \"=\", \"values\": [\"me\"]}\n      },\n      \"column_names\": [\"id\", \"subject\", \"status\", \"assigned_to\", \"due_date\"],\n      \"sort_criteria\": [[\"due_date\", \"asc\"]]\n    }\n  }' \\\n  https://redmine.example.com/extended_api/queries.json\n```\n\n**Update Query Example**:\n```bash\ncurl -X PUT \\\n  -H \"X-Redmine-API-Key: YOUR_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"query\": {\n      \"name\": \"Updated Query Name\",\n      \"filters\": {\n        \"priority_id\": {\"operator\": \"=\", \"values\": [\"4\", \"5\"]}\n      }\n    }\n  }' \\\n  https://redmine.example.com/extended_api/queries/10.json\n```\n\n**Delete Query Example**:\n```bash\ncurl -X DELETE \\\n  -H \"X-Redmine-API-Key: YOUR_KEY\" \\\n  https://redmine.example.com/extended_api/queries/10.json\n```\n\n**Query Parameters**:\n- `name` (required): Query name\n- `type`: Query type (default: \"IssueQuery\"). Options: IssueQuery, ProjectQuery, TimeEntryQuery\n- `project_id`: Project ID (null = global query)\n- `visibility`: 0=Private, 1=Roles, 2=Public\n- `filters`: Hash of filters with operators and values\n- `column_names`: Array of column names to display\n- `sort_criteria`: Array of [field, order] pairs\n- `role_ids`: Array of role IDs (required when visibility=1)\n\n**Common Filter Operators**:\n- `=`, `!`: Equals, not equals\n- `\u003e=`, `\u003c=`: Greater/less than or equal\n- `~`, `!~`: Contains, doesn't contain\n- `o`, `c`: Open, closed (for status)\n- `t`: Today, `w`: This week, `m`: This month\n- `\u003ct+N`: Less than N days from now\n- `\u003et-N`: More than N days ago\n\n### 3. Time Entries Bulk Create\n\n**POST /time_entries/bulk_create.json**\n\nCreate multiple time entries at once.\n\n**Request Body**:\n```json\n{\n  \"time_entries\": [\n    {\n      \"issue_id\": 123,\n      \"spent_on\": \"2025-01-15\",\n      \"hours\": 2.5,\n      \"activity_id\": 9,\n      \"comments\": \"Development work\"\n    },\n    {\n      \"project_id\": 5,\n      \"spent_on\": \"2025-01-15\",\n      \"hours\": 1.0,\n      \"activity_id\": 9,\n      \"comments\": \"Meeting\"\n    }\n  ]\n}\n```\n\n**Response (201 Created)** - All succeeded:\n```json\n{\n  \"created\": [\n    {\"id\": 456, \"hours\": 2.5, \"issue_id\": 123},\n    {\"id\": 457, \"hours\": 1.0, \"project_id\": 5}\n  ],\n  \"failed\": [],\n  \"summary\": {\n    \"total\": 2,\n    \"created\": 2,\n    \"failed\": 0\n  }\n}\n```\n\n**Response (207 Multi-Status)** - Partial success:\n```json\n{\n  \"created\": [{\"id\": 456, \"hours\": 2.5}],\n  \"failed\": [\n    {\n      \"index\": 1,\n      \"errors\": [\"Project or issue required\"]\n    }\n  ],\n  \"summary\": {\n    \"total\": 2,\n    \"created\": 1,\n    \"failed\": 1\n  }\n}\n```\n\n**Example**:\n```bash\ncurl -X POST \\\n  -H \"X-Redmine-API-Key: YOUR_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"time_entries\": [\n      {\"issue_id\": 123, \"spent_on\": \"2025-01-15\", \"hours\": 2.5, \"activity_id\": 9, \"comments\": \"Coding\"},\n      {\"issue_id\": 124, \"spent_on\": \"2025-01-15\", \"hours\": 1.0, \"activity_id\": 9, \"comments\": \"Review\"}\n    ]\n  }' \\\n  https://redmine.example.com/time_entries/bulk_create.json\n```\n\n## Permissions\n\nConfigure these permissions in Administration → Roles and permissions:\n\n- **manage_custom_fields_via_api**: Create/update/delete custom fields (requires admin status)\n- **manage_queries_via_api**: Create/update/delete queries (global permission)\n- **bulk_create_time_entries**: Create multiple time entries in one request (global permission)\n\nAll permissions are global and do not require per-project module enabling.\n\n## HTTP Status Codes\n\n- **200 OK**: Successful update\n- **201 Created**: Resource created successfully\n- **204 No Content**: Successful deletion\n- **207 Multi-Status**: Partial success (some items succeeded, some failed)\n- **401 Unauthorized**: Missing or invalid API key\n- **403 Forbidden**: Insufficient permissions\n- **404 Not Found**: Resource not found\n- **406 Not Acceptable**: Endpoint only accepts API requests\n- **422 Unprocessable Entity**: Validation errors\n\n## Development\n\n### Testing\n\nThis plugin uses RSpec for testing. All tests are located in the `spec/` directory.\n\n**Run all tests:**\n```bash\ncd /path/to/redmine\nbundle exec rspec plugins/redmine_extended_api/spec\n```\n\n**Run specific test file:**\n```bash\nbundle exec rspec plugins/redmine_extended_api/spec/controllers/extended_projects_controller_spec.rb\n```\n\n**Run specific test:**\n```bash\nbundle exec rspec plugins/redmine_extended_api/spec/controllers/extended_projects_controller_spec.rb:16\n```\n\n### Test Structure\n\n- **spec/controllers/** - Controller specs for API endpoints\n  - `extended_custom_fields_controller_spec.rb` - Custom fields CRUD tests (16 examples)\n  - `extended_queries_controller_spec.rb` - Queries CRUD tests (23 examples)\n  - `extended_time_entries_controller_spec.rb` - Bulk time entries tests (12 examples)\n- **spec/factories/** - FactoryBot factories for test data\n- **spec/support/** - Test helpers and configuration\n\n**Test Coverage:** 51 examples, 100% passing\n\n### Testing Features\n\n- ✅ HTTP Basic authentication testing\n- ✅ Permission and authorization testing\n- ✅ Validation error handling\n- ✅ Success and failure scenarios\n- ✅ Multi-status responses (207)\n- ✅ Edge cases and boundary conditions\n- ✅ FactoryBot for consistent test data\n- ✅ Isolated test environment\n\n## License\n\nMIT License\n\n## Author\n\nStoyan Zhekov \u003czh@zhware.net\u003e\n\n## Support\n\nReport issues at: https://github.com/zh/redmine_extended_api/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzh%2Fredmine_extended_api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzh%2Fredmine_extended_api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzh%2Fredmine_extended_api/lists"}