wikiwiki 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/README.ja.md +93 -3
- data/README.md +93 -3
- data/exe/wikiwiki +8 -0
- data/lib/wikiwiki/api.rb +38 -6
- data/lib/wikiwiki/auth/token.rb +23 -0
- data/lib/wikiwiki/auth.rb +6 -0
- data/lib/wikiwiki/cli/commands/attachment/delete.rb +48 -0
- data/lib/wikiwiki/cli/commands/attachment/get.rb +45 -0
- data/lib/wikiwiki/cli/commands/attachment/list.rb +37 -0
- data/lib/wikiwiki/cli/commands/attachment/put.rb +60 -0
- data/lib/wikiwiki/cli/commands/attachment/show.rb +44 -0
- data/lib/wikiwiki/cli/commands/auth.rb +32 -0
- data/lib/wikiwiki/cli/commands/base.rb +64 -0
- data/lib/wikiwiki/cli/commands/page/get.rb +46 -0
- data/lib/wikiwiki/cli/commands/page/list.rb +36 -0
- data/lib/wikiwiki/cli/commands/page/put.rb +40 -0
- data/lib/wikiwiki/cli/commands/page/show.rb +44 -0
- data/lib/wikiwiki/cli/formatter/json.rb +18 -0
- data/lib/wikiwiki/cli.rb +51 -0
- data/lib/wikiwiki/rate_limiter.rb +4 -12
- data/lib/wikiwiki/sliding_window.rb +1 -3
- data/lib/wikiwiki/version.rb +1 -1
- data/lib/wikiwiki/wiki.rb +7 -2
- data/lib/wikiwiki.rb +1 -1
- data/sig/dry/cli.rbs +9 -0
- data/sig/wikiwiki/api.rbs +5 -3
- data/sig/wikiwiki/auth/token.rbs +9 -0
- data/sig/wikiwiki/auth.rbs +2 -0
- data/sig/wikiwiki/cli/commands/attachment.rbs +96 -0
- data/sig/wikiwiki/cli/commands/auth.rbs +9 -0
- data/sig/wikiwiki/cli/commands/base.rbs +27 -0
- data/sig/wikiwiki/cli/commands/page.rbs +67 -0
- data/sig/wikiwiki/cli/formatter/json.rbs +9 -0
- data/sig/wikiwiki/cli.rbs +11 -0
- data/sig/wikiwiki/wiki.rbs +3 -1
- metadata +59 -8
- data/LICENSE.txt +0 -21
- data/mise.toml +0 -6
- data/rbs_collection.yaml +0 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bc13d22d549b9398dc6573d2731c7c1169fe70a1626f80d9f9b650116deb162c
|
|
4
|
+
data.tar.gz: 1495f98f015f7494f7355a76f377f42d082a72e92a4679438b2d8822f6294f91
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ad6ac01ea174e040f151f74d04504314bb4885abb0e66cc915debddee70f5d6ad3de402def7c693ae52c3ba8f1f3dd9fe8497befbb3c736ae5e79d86e79ed56a
|
|
7
|
+
data.tar.gz: 0351abf501fed5484cc1b9606610d3ed3fbc789064a11384470ee7c7abd07115c27f315568d42a4ab4ead63f5be05473bef832cfdc350afdfa04c90e76774a68
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.6.0] - 2025-11-02
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Pre-obtained token reuse support
|
|
8
|
+
- `Auth.token(token:)` for authentication with pre-obtained JWT tokens
|
|
9
|
+
- `wikiwiki auth` command to obtain authentication tokens
|
|
10
|
+
- `Wiki#token` method to retrieve the current authentication token
|
|
11
|
+
- `--token` option and `WIKIWIKI_TOKEN` environment variable support for all commands
|
|
12
|
+
- JWT token expiration validation with AuthenticationError for expired tokens
|
|
13
|
+
- Command-line interface (`wikiwiki` command) for all API operations
|
|
14
|
+
- Page commands: `list`, `show`, `get`, `put`
|
|
15
|
+
- Attachment commands: `list`, `show`, `get`, `put`, `delete`
|
|
16
|
+
- Authentication command: `auth`
|
|
17
|
+
- Environment variable support for credentials (WIKIWIKI_WIKI_ID, WIKIWIKI_TOKEN, WIKIWIKI_PASSWORD, WIKIWIKI_API_KEY_ID, WIKIWIKI_SECRET)
|
|
18
|
+
- JSON output option (`--json`) for automation
|
|
19
|
+
- Verbose (`--verbose`) and debug (`--debug`) modes
|
|
20
|
+
- File overwrite protection with `--force` flag
|
|
21
|
+
- Attachment size limit validation (512 KiB) for uploads
|
|
22
|
+
|
|
3
23
|
## [0.5.0] - 2025-10-31
|
|
4
24
|
|
|
5
25
|
### Added
|
data/README.ja.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
{file:README.md English version}
|
|
4
4
|
|
|
5
|
-
[Wikiwiki](https://wikiwiki.jp/) REST API用のRuby
|
|
5
|
+
[Wikiwiki](https://wikiwiki.jp/) REST API用のRubyクライアントライブラリおよびコマンドラインツールです。
|
|
6
6
|
|
|
7
7
|
## 概要
|
|
8
8
|
|
|
9
|
-
このgemは、Wikiwikiのwiki
|
|
9
|
+
このgemは、Wikiwikiのwikiを操作するためのRubyライブラリとCLIツールの両方を提供します。
|
|
10
10
|
|
|
11
11
|
## インストール
|
|
12
12
|
|
|
@@ -44,9 +44,91 @@ auth = Wikiwiki::Auth.password(password: "your_admin_password")
|
|
|
44
44
|
auth = Wikiwiki::Auth.api_key(api_key_id: "your_api_key_id", secret: "your_secret")
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
### トークン認証
|
|
48
|
+
|
|
49
|
+
事前に認証して得られたJWTトークンは、有効期限以内なら再利用できます:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
auth = Wikiwiki::Auth.token(token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
|
|
53
|
+
```
|
|
54
|
+
|
|
47
55
|
## 使い方
|
|
48
56
|
|
|
49
|
-
###
|
|
57
|
+
### コマンドラインインターフェース
|
|
58
|
+
|
|
59
|
+
`wikiwiki`コマンドで、すべてのAPI操作にアクセスできます:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# 環境変数で認証情報を設定(オプション)
|
|
63
|
+
export WIKIWIKI_WIKI_ID=your-wiki-id
|
|
64
|
+
export WIKIWIKI_PASSWORD=your-password
|
|
65
|
+
# または
|
|
66
|
+
export WIKIWIKI_API_KEY_ID=your-api-key-id
|
|
67
|
+
export WIKIWIKI_SECRET=your-secret
|
|
68
|
+
# または事前に取得したトークンを使用
|
|
69
|
+
export WIKIWIKI_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
70
|
+
|
|
71
|
+
# 後で使用するためにトークンを取得
|
|
72
|
+
wikiwiki auth --wiki-id=your-wiki-id --password=your-password
|
|
73
|
+
# またはexportと組み合わせて使用
|
|
74
|
+
export WIKIWIKI_TOKEN=$(wikiwiki auth --wiki-id=your-wiki-id --password=your-password)
|
|
75
|
+
|
|
76
|
+
# ページ一覧
|
|
77
|
+
wikiwiki page list
|
|
78
|
+
|
|
79
|
+
# ページのメタデータ表示
|
|
80
|
+
wikiwiki page show FrontPage
|
|
81
|
+
|
|
82
|
+
# ページのコンテンツをダウンロード
|
|
83
|
+
wikiwiki page get FrontPage
|
|
84
|
+
wikiwiki page get FrontPage frontpage.txt
|
|
85
|
+
|
|
86
|
+
# ページをアップロード/更新(標準入力またはファイルから)
|
|
87
|
+
wikiwiki page put TestPage < content.txt
|
|
88
|
+
wikiwiki page put TestPage content.txt
|
|
89
|
+
|
|
90
|
+
# 添付ファイル一覧
|
|
91
|
+
wikiwiki attachment list FrontPage
|
|
92
|
+
|
|
93
|
+
# 添付ファイルのメタデータ表示
|
|
94
|
+
wikiwiki attachment show FrontPage logo.png
|
|
95
|
+
|
|
96
|
+
# 添付ファイルをダウンロード
|
|
97
|
+
wikiwiki attachment get FrontPage logo.png
|
|
98
|
+
wikiwiki attachment get FrontPage logo.png --directory downloads/
|
|
99
|
+
|
|
100
|
+
# 添付ファイルをアップロード(最大512 KiB)
|
|
101
|
+
wikiwiki attachment put FrontPage image.png
|
|
102
|
+
wikiwiki attachment put FrontPage local.png --name remote.png
|
|
103
|
+
|
|
104
|
+
# 添付ファイルを削除
|
|
105
|
+
wikiwiki attachment delete FrontPage logo.png
|
|
106
|
+
|
|
107
|
+
# 既存のファイル/添付ファイルを上書きするには --force を使用
|
|
108
|
+
wikiwiki page get FrontPage existing.txt --force
|
|
109
|
+
wikiwiki attachment put FrontPage logo.png --force
|
|
110
|
+
|
|
111
|
+
# 注意: --force による添付ファイルの上書きはアトミックではありません。
|
|
112
|
+
# 既存の添付ファイルを削除してから新しいファイルをアップロードします。
|
|
113
|
+
# アップロードに失敗した場合、添付ファイルは失われます。
|
|
114
|
+
|
|
115
|
+
# コマンドラインで認証情報を指定(環境変数より優先)
|
|
116
|
+
wikiwiki --wiki-id=your-wiki-id --password=your-password page list
|
|
117
|
+
wikiwiki --wiki-id=your-wiki-id --api-key-id=id --secret=secret page list
|
|
118
|
+
wikiwiki --wiki-id=your-wiki-id --token=eyJ... page list
|
|
119
|
+
|
|
120
|
+
# 自動化のためのJSON出力
|
|
121
|
+
wikiwiki page list --json
|
|
122
|
+
wikiwiki attachment show FrontPage logo.png --json
|
|
123
|
+
|
|
124
|
+
# 詳細モードとデバッグモード
|
|
125
|
+
wikiwiki page list --verbose
|
|
126
|
+
wikiwiki page list --debug
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Rubyライブラリ
|
|
130
|
+
|
|
131
|
+
ライブラリを使用する基本的な例:
|
|
50
132
|
|
|
51
133
|
```ruby
|
|
52
134
|
require "wikiwiki"
|
|
@@ -55,6 +137,14 @@ require "wikiwiki"
|
|
|
55
137
|
auth = Wikiwiki::Auth.password(password: "admin_password")
|
|
56
138
|
wiki = Wikiwiki::Wiki.new(wiki_id: "your-wiki-id", auth:)
|
|
57
139
|
|
|
140
|
+
# 認証トークンを取得して再利用
|
|
141
|
+
token = wiki.token
|
|
142
|
+
# トークンを保存して後で使用...
|
|
143
|
+
|
|
144
|
+
# 後で保存したトークンを使用
|
|
145
|
+
auth = Wikiwiki::Auth.token(token: token)
|
|
146
|
+
wiki = Wikiwiki::Wiki.new(wiki_id: "your-wiki-id", auth:)
|
|
147
|
+
|
|
58
148
|
# すべてのページ名の一覧を取得
|
|
59
149
|
page_names = wiki.page_names
|
|
60
150
|
# => ["FrontPage", "SideBar", ...]
|
data/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
{file:README.ja.md 日本語版}
|
|
4
4
|
|
|
5
|
-
A Ruby client library for the [Wikiwiki](https://wikiwiki.jp/) REST API.
|
|
5
|
+
A Ruby client library and command-line interface for the [Wikiwiki](https://wikiwiki.jp/) REST API.
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
8
8
|
|
|
9
|
-
This gem provides a
|
|
9
|
+
This gem provides both a Ruby library and CLI tool to interact with Wikiwiki wikis.
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -44,9 +44,91 @@ auth = Wikiwiki::Auth.password(password: "your_admin_password")
|
|
|
44
44
|
auth = Wikiwiki::Auth.api_key(api_key_id: "your_api_key_id", secret: "your_secret")
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
### Token Authentication
|
|
48
|
+
|
|
49
|
+
A JWT token obtained from a previous authentication can be reused within its validity period:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
auth = Wikiwiki::Auth.token(token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
|
|
53
|
+
```
|
|
54
|
+
|
|
47
55
|
## Usage
|
|
48
56
|
|
|
49
|
-
###
|
|
57
|
+
### Command Line Interface
|
|
58
|
+
|
|
59
|
+
The `wikiwiki` command provides access to all API operations:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Set credentials via environment variables (optional)
|
|
63
|
+
export WIKIWIKI_WIKI_ID=your-wiki-id
|
|
64
|
+
export WIKIWIKI_PASSWORD=your-password
|
|
65
|
+
# or
|
|
66
|
+
export WIKIWIKI_API_KEY_ID=your-api-key-id
|
|
67
|
+
export WIKIWIKI_SECRET=your-secret
|
|
68
|
+
# or use a pre-obtained token
|
|
69
|
+
export WIKIWIKI_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
70
|
+
|
|
71
|
+
# Obtain a token for later use
|
|
72
|
+
wikiwiki auth --wiki-id=your-wiki-id --password=your-password
|
|
73
|
+
# or combine with export
|
|
74
|
+
export WIKIWIKI_TOKEN=$(wikiwiki auth --wiki-id=your-wiki-id --password=your-password)
|
|
75
|
+
|
|
76
|
+
# List pages
|
|
77
|
+
wikiwiki page list
|
|
78
|
+
|
|
79
|
+
# Show page metadata
|
|
80
|
+
wikiwiki page show FrontPage
|
|
81
|
+
|
|
82
|
+
# Download page content
|
|
83
|
+
wikiwiki page get FrontPage
|
|
84
|
+
wikiwiki page get FrontPage frontpage.txt
|
|
85
|
+
|
|
86
|
+
# Upload/update page (from stdin or file)
|
|
87
|
+
wikiwiki page put TestPage < content.txt
|
|
88
|
+
wikiwiki page put TestPage content.txt
|
|
89
|
+
|
|
90
|
+
# List attachments
|
|
91
|
+
wikiwiki attachment list FrontPage
|
|
92
|
+
|
|
93
|
+
# Show attachment metadata
|
|
94
|
+
wikiwiki attachment show FrontPage logo.png
|
|
95
|
+
|
|
96
|
+
# Download attachment
|
|
97
|
+
wikiwiki attachment get FrontPage logo.png
|
|
98
|
+
wikiwiki attachment get FrontPage logo.png --directory downloads/
|
|
99
|
+
|
|
100
|
+
# Upload attachment (max 512 KiB)
|
|
101
|
+
wikiwiki attachment put FrontPage image.png
|
|
102
|
+
wikiwiki attachment put FrontPage local.png --name remote.png
|
|
103
|
+
|
|
104
|
+
# Delete attachment
|
|
105
|
+
wikiwiki attachment delete FrontPage logo.png
|
|
106
|
+
|
|
107
|
+
# Use --force to overwrite existing files/attachments
|
|
108
|
+
wikiwiki page get FrontPage existing.txt --force
|
|
109
|
+
wikiwiki attachment put FrontPage logo.png --force
|
|
110
|
+
|
|
111
|
+
# Note: Attachment overwrite with --force is not atomic.
|
|
112
|
+
# The existing attachment is deleted before uploading the new one.
|
|
113
|
+
# If the upload fails, the attachment will be lost.
|
|
114
|
+
|
|
115
|
+
# Authentication via command line (overrides environment variables)
|
|
116
|
+
wikiwiki --wiki-id=your-wiki-id --password=your-password page list
|
|
117
|
+
wikiwiki --wiki-id=your-wiki-id --api-key-id=id --secret=secret page list
|
|
118
|
+
wikiwiki --wiki-id=your-wiki-id --token=eyJ... page list
|
|
119
|
+
|
|
120
|
+
# JSON output for automation
|
|
121
|
+
wikiwiki page list --json
|
|
122
|
+
wikiwiki attachment show FrontPage logo.png --json
|
|
123
|
+
|
|
124
|
+
# Verbose and debug modes
|
|
125
|
+
wikiwiki page list --verbose
|
|
126
|
+
wikiwiki page list --debug
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Ruby Library
|
|
130
|
+
|
|
131
|
+
Basic example using the library:
|
|
50
132
|
|
|
51
133
|
```ruby
|
|
52
134
|
require "wikiwiki"
|
|
@@ -55,6 +137,14 @@ require "wikiwiki"
|
|
|
55
137
|
auth = Wikiwiki::Auth.password(password: "admin_password")
|
|
56
138
|
wiki = Wikiwiki::Wiki.new(wiki_id: "your-wiki-id", auth:)
|
|
57
139
|
|
|
140
|
+
# Obtain and reuse authentication token
|
|
141
|
+
token = wiki.token
|
|
142
|
+
# Save token for later use...
|
|
143
|
+
|
|
144
|
+
# Later, use the saved token
|
|
145
|
+
auth = Wikiwiki::Auth.token(token: token)
|
|
146
|
+
wiki = Wikiwiki::Wiki.new(wiki_id: "your-wiki-id", auth:)
|
|
147
|
+
|
|
58
148
|
# List all page names
|
|
59
149
|
page_names = wiki.page_names
|
|
60
150
|
# => ["FrontPage", "SideBar", ...]
|
data/exe/wikiwiki
ADDED
data/lib/wikiwiki/api.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "jwt"
|
|
4
5
|
require "net/http"
|
|
5
6
|
require "uri"
|
|
6
7
|
|
|
@@ -13,6 +14,7 @@ module Wikiwiki
|
|
|
13
14
|
# pages = api.get_pages
|
|
14
15
|
class API
|
|
15
16
|
attr_reader :logger
|
|
17
|
+
attr_reader :token
|
|
16
18
|
|
|
17
19
|
BASE_URL = URI.parse("https://api.wikiwiki.jp").freeze
|
|
18
20
|
private_constant :BASE_URL
|
|
@@ -123,14 +125,44 @@ module Wikiwiki
|
|
|
123
125
|
|
|
124
126
|
# Authenticate with the Wikiwiki API
|
|
125
127
|
#
|
|
126
|
-
# @param auth [Auth::Password, Auth::ApiKey] authentication credentials
|
|
128
|
+
# @param auth [Auth::Password, Auth::ApiKey, Auth::Token] authentication credentials
|
|
127
129
|
# @return [String] JWT token
|
|
128
130
|
# @raise [Error] if authentication fails
|
|
129
131
|
private def authenticate(auth)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
token = if auth.is_a?(Auth::Token)
|
|
133
|
+
auth.token
|
|
134
|
+
else
|
|
135
|
+
uri = BASE_URL + "/#{wiki_id}/auth"
|
|
136
|
+
response = request(:post, uri, body: auth.to_h, authenticate: false)
|
|
137
|
+
data = parse_json_response(response)
|
|
138
|
+
data["token"]
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
validate_token_expiry(token) if auth.is_a?(Auth::Token)
|
|
142
|
+
token
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Validate JWT token expiry
|
|
146
|
+
#
|
|
147
|
+
# @param token [String] JWT token
|
|
148
|
+
# @return [void]
|
|
149
|
+
# @raise [AuthenticationError] if token has expired
|
|
150
|
+
private def validate_token_expiry(token)
|
|
151
|
+
payload, = JWT.decode(token, nil, false)
|
|
152
|
+
exp = payload["exp"]
|
|
153
|
+
|
|
154
|
+
if exp
|
|
155
|
+
exp_time = Time.at(exp)
|
|
156
|
+
if Time.now >= exp_time
|
|
157
|
+
raise AuthenticationError, "Token has expired at #{exp_time.iso8601}"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
logger.debug("[#{wiki_id}] Token expires at: #{exp_time.iso8601}")
|
|
161
|
+
else
|
|
162
|
+
logger.debug("[#{wiki_id}] Token has no expiration")
|
|
163
|
+
end
|
|
164
|
+
rescue JWT::DecodeError => e
|
|
165
|
+
logger.debug("[#{wiki_id}] Failed to decode token: #{e.message}")
|
|
134
166
|
end
|
|
135
167
|
|
|
136
168
|
# Parse JSON response
|
|
@@ -217,6 +249,6 @@ module Wikiwiki
|
|
|
217
249
|
end
|
|
218
250
|
end
|
|
219
251
|
|
|
220
|
-
private attr_reader :wiki_id
|
|
252
|
+
private attr_reader :wiki_id
|
|
221
253
|
end
|
|
222
254
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wikiwiki
|
|
4
|
+
module Auth
|
|
5
|
+
# Token-based authentication using a pre-obtained JWT token
|
|
6
|
+
#
|
|
7
|
+
# This allows using a previously obtained authentication token without
|
|
8
|
+
# re-authenticating with password or API key credentials.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
12
|
+
# auth = Wikiwiki::Auth.token(token: token)
|
|
13
|
+
# wiki = Wikiwiki::Wiki.new(wiki_id: "my-wiki", auth: auth)
|
|
14
|
+
Token = Data.define(:token)
|
|
15
|
+
|
|
16
|
+
class Token
|
|
17
|
+
# Reopen the class to add YARD documentation for attributes
|
|
18
|
+
|
|
19
|
+
# @!attribute [r] token
|
|
20
|
+
# @return [String] the JWT token
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/wikiwiki/auth.rb
CHANGED
|
@@ -17,5 +17,11 @@ module Wikiwiki
|
|
|
17
17
|
# @param secret [String] secret key
|
|
18
18
|
# @return [ApiKey] API key authentication object
|
|
19
19
|
def self.api_key(api_key_id:, secret:) = ApiKey.new(api_key_id:, secret:)
|
|
20
|
+
|
|
21
|
+
# Create token-based authentication credentials
|
|
22
|
+
#
|
|
23
|
+
# @param token [String] JWT authentication token
|
|
24
|
+
# @return [Token] token authentication object
|
|
25
|
+
def self.token(token:) = Token.new(token:)
|
|
20
26
|
end
|
|
21
27
|
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wikiwiki
|
|
4
|
+
class CLI
|
|
5
|
+
module Commands
|
|
6
|
+
module Attachment
|
|
7
|
+
# Delete attachment from a page
|
|
8
|
+
class Delete < Base
|
|
9
|
+
desc "Delete attachment from a page"
|
|
10
|
+
|
|
11
|
+
argument :page_name, required: true, desc: "Page name"
|
|
12
|
+
argument :file_name, required: true, desc: "Attachment file name"
|
|
13
|
+
|
|
14
|
+
# Execute the delete command
|
|
15
|
+
#
|
|
16
|
+
# @param page_name [String] name of the page
|
|
17
|
+
# @param file_name [String] name of the attachment file to delete
|
|
18
|
+
# @param out [IO] output stream
|
|
19
|
+
# @param err [IO] error stream
|
|
20
|
+
# @return [void]
|
|
21
|
+
def call(page_name:, file_name:, out: $stdout, err: $stderr, **)
|
|
22
|
+
wiki = create_wiki(out:, err:, **)
|
|
23
|
+
|
|
24
|
+
# Check if page exists first
|
|
25
|
+
unless page_exists?(wiki, page_name:)
|
|
26
|
+
raise ArgumentError, "Page '#{page_name}' does not exist"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Check if attachment exists
|
|
30
|
+
unless attachment_exists?(wiki, page_name:, attachment_name: file_name)
|
|
31
|
+
raise ArgumentError, "Attachment '#{file_name}' does not exist on page '#{page_name}'"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
wiki.delete_attachment(page_name:, attachment_name: file_name)
|
|
35
|
+
|
|
36
|
+
say("Attachment '#{file_name}' deleted from page '#{page_name}'", out:, **)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private def page_exists?(wiki, page_name:) = wiki.page_names.include?(page_name)
|
|
40
|
+
|
|
41
|
+
private def attachment_exists?(wiki, page_name:, attachment_name:) = wiki.attachment_names(page_name:).include?(attachment_name)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
register "attachment delete", Attachment::Delete
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wikiwiki
|
|
4
|
+
class CLI
|
|
5
|
+
module Commands
|
|
6
|
+
module Attachment
|
|
7
|
+
# Download attachment from a page
|
|
8
|
+
class Get < Base
|
|
9
|
+
desc "Download attachment from a page"
|
|
10
|
+
|
|
11
|
+
argument :page_name, required: true, desc: "Page name"
|
|
12
|
+
argument :file_name, required: true, desc: "Attachment file name"
|
|
13
|
+
option :directory, aliases: ["-d"], desc: "Download directory (current directory if omitted)"
|
|
14
|
+
option :force, aliases: ["-f"], type: :boolean, default: false, desc: "Overwrite existing file"
|
|
15
|
+
|
|
16
|
+
# Execute the get command
|
|
17
|
+
#
|
|
18
|
+
# @param page_name [String] name of the page
|
|
19
|
+
# @param file_name [String] name of the attachment file
|
|
20
|
+
# @param directory [String, nil] optional download directory
|
|
21
|
+
# @param force [Boolean] whether to overwrite existing file
|
|
22
|
+
# @param out [IO] output stream
|
|
23
|
+
# @param err [IO] error stream
|
|
24
|
+
# @return [void]
|
|
25
|
+
def call(page_name:, file_name:, directory: nil, force: false, out: $stdout, err: $stderr, **)
|
|
26
|
+
wiki = create_wiki(out:, err:, **)
|
|
27
|
+
|
|
28
|
+
output_path = directory ? File.join(directory, file_name) : file_name
|
|
29
|
+
|
|
30
|
+
if File.exist?(output_path) && !force
|
|
31
|
+
raise ArgumentError, "File '#{output_path}' already exists. Use --force to overwrite."
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
attachment = wiki.attachment(page_name:, attachment_name: file_name)
|
|
35
|
+
File.binwrite(output_path, attachment.content)
|
|
36
|
+
|
|
37
|
+
say("Attachment '#{file_name}' (#{attachment.content.bytesize} bytes) saved to #{output_path}", out:, **)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
register "attachment get", Attachment::Get
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wikiwiki
|
|
4
|
+
class CLI
|
|
5
|
+
module Commands
|
|
6
|
+
# Attachment-related commands
|
|
7
|
+
module Attachment
|
|
8
|
+
# List attachments on a page
|
|
9
|
+
class List < Base
|
|
10
|
+
desc "List attachments on a page"
|
|
11
|
+
|
|
12
|
+
argument :page_name, required: true, desc: "Page name"
|
|
13
|
+
option :json, aliases: ["-j"], type: :boolean, default: false, desc: "Output as JSON"
|
|
14
|
+
|
|
15
|
+
# Execute the list command
|
|
16
|
+
#
|
|
17
|
+
# @param page_name [String] name of the page
|
|
18
|
+
# @param options [Hash] command options including wiki_id, auth, json, verbose, out, err
|
|
19
|
+
# @return [void]
|
|
20
|
+
def call(page_name:, out: $stdout, err: $stderr, **options)
|
|
21
|
+
wiki = create_wiki(out:, err:, **options)
|
|
22
|
+
attachment_names = wiki.attachment_names(page_name:)
|
|
23
|
+
|
|
24
|
+
if options[:json]
|
|
25
|
+
out.puts Formatter::JSON.new.format(attachment_names)
|
|
26
|
+
else
|
|
27
|
+
attachment_names.each {|name| out.puts name }
|
|
28
|
+
say("#{attachment_names.size} attachments found", out:, **options)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
register "attachment list", Attachment::List
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wikiwiki
|
|
4
|
+
class CLI
|
|
5
|
+
module Commands
|
|
6
|
+
module Attachment
|
|
7
|
+
# Upload attachment to a page
|
|
8
|
+
class Put < Base
|
|
9
|
+
desc "Upload attachment to a page"
|
|
10
|
+
|
|
11
|
+
MAX_ATTACHMENT_SIZE = 512 * 1024 # 512 KiB
|
|
12
|
+
private_constant :MAX_ATTACHMENT_SIZE
|
|
13
|
+
|
|
14
|
+
argument :page_name, required: true, desc: "Page name"
|
|
15
|
+
argument :file_path, required: true, desc: "Local file path"
|
|
16
|
+
option :name, aliases: ["-n"], desc: "Attachment name (inferred from file path if omitted)"
|
|
17
|
+
option :force, aliases: ["-f"], type: :boolean, default: false, desc: "Overwrite existing attachment (non-atomic: deletes then uploads)"
|
|
18
|
+
|
|
19
|
+
# Execute the put command
|
|
20
|
+
#
|
|
21
|
+
# @param page_name [String] name of the page
|
|
22
|
+
# @param file_path [String] local file path to upload
|
|
23
|
+
# @param name [String, nil] optional attachment name (inferred from file_path if nil)
|
|
24
|
+
# @param force [Boolean] whether to overwrite existing attachment
|
|
25
|
+
# @param out [IO] output stream
|
|
26
|
+
# @param err [IO] error stream
|
|
27
|
+
# @return [void]
|
|
28
|
+
def call(page_name:, file_path:, name: nil, force: false, out: $stdout, err: $stderr, **)
|
|
29
|
+
wiki = create_wiki(out:, err:, **)
|
|
30
|
+
|
|
31
|
+
attachment_name = name || File.basename(file_path)
|
|
32
|
+
content = File.binread(file_path)
|
|
33
|
+
|
|
34
|
+
if content.bytesize > MAX_ATTACHMENT_SIZE
|
|
35
|
+
raise ArgumentError, "File size (#{content.bytesize} bytes) exceeds maximum allowed size (#{MAX_ATTACHMENT_SIZE} bytes / 512 KiB)"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if attachment_exists?(wiki, page_name:, attachment_name:)
|
|
39
|
+
raise ArgumentError, "Attachment '#{attachment_name}' already exists. Use --force to overwrite." unless force
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
wiki.delete_attachment(page_name:, attachment_name:)
|
|
43
|
+
rescue ResourceNotFoundError
|
|
44
|
+
# Already deleted by another process, continue
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
wiki.add_attachment(page_name:, attachment_name:, content:)
|
|
49
|
+
|
|
50
|
+
say("Attachment '#{attachment_name}' uploaded to page '#{page_name}'", out:, **)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private def attachment_exists?(wiki, page_name:, attachment_name:) = wiki.attachment_names(page_name:).include?(attachment_name)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
register "attachment put", Attachment::Put
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wikiwiki
|
|
4
|
+
class CLI
|
|
5
|
+
module Commands
|
|
6
|
+
module Attachment
|
|
7
|
+
# Show attachment metadata
|
|
8
|
+
class Show < Base
|
|
9
|
+
desc "Show attachment metadata"
|
|
10
|
+
|
|
11
|
+
argument :page_name, required: true, desc: "Page name"
|
|
12
|
+
argument :file_name, required: true, desc: "Attachment file name"
|
|
13
|
+
option :json, aliases: ["-j"], type: :boolean, default: false, desc: "Output as JSON"
|
|
14
|
+
|
|
15
|
+
# Execute the show command
|
|
16
|
+
#
|
|
17
|
+
# @param page_name [String] name of the page
|
|
18
|
+
# @param file_name [String] name of the attachment file
|
|
19
|
+
# @param options [Hash] command options including wiki_id, auth, json, verbose, out, err
|
|
20
|
+
# @return [void]
|
|
21
|
+
def call(page_name:, file_name:, out: $stdout, err: $stderr, **options)
|
|
22
|
+
wiki = create_wiki(out:, err:, **options)
|
|
23
|
+
attachment = wiki.attachment(page_name:, attachment_name: file_name)
|
|
24
|
+
|
|
25
|
+
metadata = attachment.to_h.except(:content).transform_values {|v| v.is_a?(Time) ? v.iso8601 : v }
|
|
26
|
+
|
|
27
|
+
if options[:json]
|
|
28
|
+
out.puts Formatter::JSON.new.format(metadata)
|
|
29
|
+
else
|
|
30
|
+
out.puts "Page: #{metadata[:page_name]}"
|
|
31
|
+
out.puts "Name: #{metadata[:name]}"
|
|
32
|
+
out.puts "Size: #{metadata[:size]} bytes"
|
|
33
|
+
out.puts "Time: #{metadata[:time]}"
|
|
34
|
+
out.puts "Type: #{metadata[:type]}"
|
|
35
|
+
say("Attachment metadata retrieved", out:, **options)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
register "attachment show", Attachment::Show
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wikiwiki
|
|
4
|
+
class CLI
|
|
5
|
+
module Commands
|
|
6
|
+
# Authenticate and output JWT token
|
|
7
|
+
class Auth < Base
|
|
8
|
+
desc "Authenticate and output JWT token"
|
|
9
|
+
|
|
10
|
+
option :json, aliases: ["-j"], type: :boolean, default: false, desc: "Output as JSON"
|
|
11
|
+
|
|
12
|
+
# Execute the auth command
|
|
13
|
+
#
|
|
14
|
+
# @param options [Hash] command options including wiki_id, auth credentials, json, verbose, out, err
|
|
15
|
+
# @return [void]
|
|
16
|
+
def call(out: $stdout, err: $stderr, **options)
|
|
17
|
+
wiki = create_wiki(out:, err:, **options)
|
|
18
|
+
token = wiki.token
|
|
19
|
+
|
|
20
|
+
if options[:json]
|
|
21
|
+
out.puts Formatter::JSON.new.format({"token" => token})
|
|
22
|
+
else
|
|
23
|
+
out.puts token
|
|
24
|
+
say("Authentication successful", out:, **options)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
register "auth", Auth
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|