notion_ruby_mapping 0.7.4 → 0.7.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc53f7256d1ce820695e6f2dc28149ef945dd0ddf765fd933b90882212335d0c
4
- data.tar.gz: 625c42250124c4e66d8016812c8a8bd53d02cef88c0061320fdd2ea8c996cd28
3
+ metadata.gz: f757b8eab76be0d30120c595afffc53dba4cde99a872c53eae58334d6d1ecd73
4
+ data.tar.gz: d342baef240aaf0cbabc1b9fe298eb99216367e72eeb9c0ed49f15bc58ffc930
5
5
  SHA512:
6
- metadata.gz: 573470cad7c6c10bb683417cb0ae62ed33819cb3471db31f3eb9b10d5718204c801fd7e42a063a69c1753dd7739f80777fa265fee073d5bd1abd1f17b29320ff
7
- data.tar.gz: 2b76551f53c23564645aff1c027fe8521d13f0451e6cb43bbd7f66551e784a35bbcc0b1aa0ca4d12df5f35aa5d277570ae12415963a8c51de098574d67c66804
6
+ metadata.gz: 4e043303f49438475ef9ef87b2e7d91af74105bf2069286986d9727622e4056c8e9ab6921b3c06c55f24a3c10ad6ecb9b103fec88ddb3f90fde482fad6fc90dd
7
+ data.tar.gz: 30934684ec64206c5fcb6123dea99fdaa6fd3721ecb3ace0a1574980e2c93eb4ee4d2574f09c9eefb98a5b01fce761b2c4c09e5ab7a8b46f36d9bd3714615cee
data/README.md CHANGED
@@ -119,6 +119,7 @@ NotionRubyMapping.configuration { |c| c.notion_token = ENV["NOTION_API_TOKEN"] }
119
119
  4. [Create ER Diagram from Notion database / Notion データベースの ER 図を作成](https://hkob.notion.site/notionErDiagram-Sample-1720c2199c534ca08138cde38f31f710)
120
120
  5. [Create Sitemap from Notion pages / Notion page からサイトマップを作成](https://hkob.notion.site/notionSitemap-sample-14e195c83d024c5382aab09210916c87)
121
121
  6. [Create Notion databases from ER Diagram / ER 図から Notion データベースを作成](https://hkob.notion.site/erdToNotionDb-sample-87e5e52a6b9f46abbdeebcb3c902a516)
122
+ 6. [NotionTimeRecorder & GTD template](https://hkob.notion.site/NotionTimeRecorder-GTD-template-8c4b5813dbbe4774a517314c9b20bafa)
122
123
 
123
124
  ### 2.5 API reference / API リファレンス
124
125
 
@@ -126,6 +127,7 @@ NotionRubyMapping.configuration { |c| c.notion_token = ENV["NOTION_API_TOKEN"] }
126
127
 
127
128
  ## 3. ChangeLog
128
129
 
130
+ - 2023/3/8 [v0.7.5] add notionTimeRecorder.rb
129
131
  - 2023/2/9 [v0.7.4] bug fix for rollup property of erdToNotionRb.rb script
130
132
  - 2023/1/26 [v0.7.3] release beta version of erdToNotionRb.rb script
131
133
  - 2023/1/25 [v0.7.2] bug fix for creating relation property / add erdToNotionRb.rb script
@@ -0,0 +1,284 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require "tk"
4
+ require "notion_ruby_mapping"
5
+ require "yaml"
6
+ require "time"
7
+ include Tk
8
+ include NotionRubyMapping
9
+
10
+ CONF_FILE_NAME = "#{ENV["HOME"]}/.notionTimeRecorder.yml"
11
+
12
+ class TaskConf
13
+ KEY_TO_METHOD = {
14
+ api_key: "NOTION_API_KEY",
15
+ db_id: "TASK_DB_ID",
16
+ tpn: "TITLE_PROPERTY_NAME",
17
+ dpn: "DATE_PROPERTY_NAME",
18
+ fpn: "FINISH_PROPERTY_NAME",
19
+ fpt: "FINISH_PROPERTY_TYPE",
20
+ ipv: "IN_PROGRESS_PROPERTY_VALUE",
21
+ fpv: "FINISH_PROPERTY_VALUE",
22
+ bln: "BLOCKING_PROPERTY_NAME",
23
+ bbn: "BLOCKED_BY_PROPERTY_NAME",
24
+ ppd: "PERCENT_PREVIOUS_DONE_FUNC_NAME",
25
+ }
26
+
27
+ # @param [Boolean] force_setup
28
+ def initialize(yaml_name, force_setup = false)
29
+ @yaml_name = yaml_name
30
+ @config = {}
31
+ setup(force_setup) if force_setup || !File.exist?(@yaml_name)
32
+ load_conf
33
+ end
34
+
35
+ # @param [Boolean] force_setup
36
+ def setup(force_setup)
37
+ load_conf if force_setup
38
+ @variables = {}
39
+ @conf_frame = TkLabelFrame.new(nil, text: "Configuration").pack(padx: 10, pady: 10)
40
+ KEY_TO_METHOD.each do |method, key|
41
+ @variables[method] = TkVariable.new @config[key]&.to_s
42
+ label_frame = TkLabelFrame.new(@conf_frame, text: key).pack(padx: 10, pady: 5)
43
+ if method == :fpt
44
+ TkRadioButton.new(label_frame, text: "status", variable: @variables[method], value: "status").pack
45
+ TkRadioButton.new(label_frame, text: "checkbox", variable: @variables[method], value: "checkbox").pack
46
+ else
47
+ TkEntry.new(label_frame, textvariable: @variables[method]).pack
48
+ end
49
+ end
50
+ cmd_frame = TkFrame.new(@conf_frame).pack
51
+ TkButton.new(cmd_frame, text: "Quit", command: ->{ exit }).pack(side: :left)
52
+ TkButton.new(cmd_frame, text: "Save", command: ->{ save }).pack(side: :right)
53
+ Tk.mainloop
54
+ end
55
+
56
+ def load_conf
57
+ @config = YAML.load_file @yaml_name
58
+ KEY_TO_METHOD.each do |method, key|
59
+ self.class.define_method(method) { @config[key] }
60
+ end
61
+ end
62
+
63
+ def save
64
+ KEY_TO_METHOD.each do |method, key|
65
+ @config[key] = @variables[method].value.chomp
66
+ end
67
+ @config["FINISH_PROPERTY_VALUE"] = true if @config["FINISH_PROPERTY_VALUE"] == "true"
68
+ File.open(@yaml_name, "w") do |f|
69
+ YAML.dump @config, f
70
+ end
71
+ load_conf
72
+ @conf_frame.destroy
73
+ @task_cache = TaskCache.new self
74
+ end
75
+ end
76
+
77
+ class Task
78
+ # @param [NotionRubyMapping::Page] page
79
+ # @param [TaskCache] tc
80
+ def initialize(page, tc)
81
+ @page = page
82
+ @tc = tc
83
+ @conf = tc.conf
84
+ @date_property = @page.properties[@conf.dpn]
85
+ @finish_property = @page.properties[@conf.fpn]
86
+ @finish = (@conf.fpt == "status" ? @finish_property.status_name : @finish_property.checkbox) == @conf.fpv
87
+ @start_date = @date_property.start_date_obj
88
+ @end_date = @date_property.end_date_obj
89
+ end
90
+
91
+ def save
92
+ @page.save
93
+ @start_date = @date_property.start_date_obj
94
+ @end_date = @date_property.end_date_obj
95
+ @finish = (@conf.fpt == "status" ? @finish_property.status_name : @finish_property.checkbox) == @conf.fpv
96
+ end
97
+
98
+ def start_time_str
99
+ @start_date.nil? || @start_date.is_a?(Date) ? "-" : @start_date.strftime("%H:%M")
100
+ end
101
+
102
+ def end_time_str
103
+ @end_date.nil? || @end_date.is_a?(Date) ? "-" : @end_date.strftime("%H:%M")
104
+ end
105
+
106
+ def state
107
+ @finish ? "disabled" : "normal"
108
+ end
109
+
110
+ def time_recording(force_set_date = false)
111
+ if @start_date.nil? || force_set_date
112
+ @date_property.start_date = Date.today
113
+ @date_property.end_date = nil
114
+ save
115
+ @tc.move_to_today self
116
+ elsif @start_date.is_a?(Date)
117
+ @date_property.start_date = Time.now
118
+ @finish_property.send("#{@conf.fpt}=", @conf.ipv) unless @conf.ipv.empty?
119
+ @date_property.end_date = nil
120
+ save
121
+ @tc.update_today_tasks
122
+ else
123
+ @date_property.start_date = @date_property.start_date_obj
124
+ @date_property.end_date = Time.now
125
+ @finish_property.send("#{@conf.fpt}=", @conf.fpv)
126
+ save
127
+ if blocking_count&.positive?
128
+ @tc.reload_someday
129
+ @tc.update_today_tasks
130
+ else
131
+ @tc.update_today_tasks
132
+ end
133
+ end
134
+ end
135
+
136
+ def blocking_count
137
+ @conf.bln.empty? ? nil : @page.properties[@conf.bln].relation.count
138
+ end
139
+
140
+ def view_task(frame, index, today_task = true)
141
+ TkButton.new(frame, text: @page.title, state: state, command: -> { time_recording }).grid(row: index, column: 0)
142
+ if today_task
143
+ TkLabel.new(frame, text: start_time_str).grid(row: index, column: 1)
144
+ TkLabel.new(frame, text: end_time_str).grid(row: index, column: 2)
145
+ elsif (bcnt = blocking_count)
146
+ TkLabel.new(frame, text: "+#{bcnt}").grid(row: index, column: 1)
147
+ end
148
+ end
149
+ end
150
+
151
+ class TaskCache
152
+ # @param [TaskConf] conf
153
+ def initialize(conf)
154
+ @conf = conf
155
+ NotionRubyMapping.configure do |c|
156
+ c.notion_token = @conf.api_key
157
+ end
158
+
159
+ @db = Database.find conf.db_id
160
+ @db_date_property, @db_finish_property = @db.properties.values_at @conf.dpn, @conf.fpn
161
+ @today_tasks = []
162
+ @someday_tasks = []
163
+ @unfinished_tasks = []
164
+ @new_today_task_val = TkVariable.new
165
+ create_view
166
+ end
167
+ attr_reader :conf
168
+
169
+ def create_view
170
+ @today_outer_frame = TkLabelFrame.new(nil, text: "Today's tasks").pack(padx: 10, pady: 5)
171
+ @today_inner_frame = nil
172
+ @someday_outer_frame = TkLabelFrame.new(nil, text: "Someday").pack(padx: 10, pady: 5)
173
+ @someday_inner_frame = nil
174
+ @new_frame = TkLabelFrame.new(nil, text: "New task").pack(padx: 10, pady: 5)
175
+ entry = TkEntry.new(@new_frame, textvariable: @new_today_task_val).pack(side: :left)
176
+ entry.focus
177
+ entry.bind("Return", -> { add_someday_task })
178
+ TkButton.new(@new_frame, text: "Add", command: -> { add_someday_task }).pack(side: :right)
179
+
180
+ cmd_frame = TkFrame.new(nil).pack(pady: 5)
181
+ TkButton.new(cmd_frame, text: "Reload", command: ->{ reload }).pack(side: :left)
182
+ TkButton.new(cmd_frame, text: "Quit", command: ->{ exit }).pack(side: :right)
183
+ reload
184
+ end
185
+
186
+ def reload
187
+ NotionCache.instance.clear_object_hash
188
+ load_today_tasks
189
+ load_unfinished_tasks
190
+ update_today_tasks
191
+ load_someday_tasks
192
+ update_someday_tasks
193
+ end
194
+
195
+ def reload_someday
196
+ NotionCache.instance.clear_object_hash
197
+ load_someday_tasks
198
+ update_someday_tasks
199
+ end
200
+
201
+ def load_unfinished_tasks
202
+ now = Time.now
203
+ end_of_day = Time.local(now.year, now.month, now.mday, 23, 59, 59) - 86400
204
+ query = @db_date_property.filter_before(end_of_day)
205
+ .and(@db_finish_property.filter_does_not_equal(@conf.fpv))
206
+ @unfinished_tasks = @db.query_database(query).map { |tp| Task.new tp, self }
207
+ end
208
+
209
+ def load_today_tasks
210
+ query = @db_date_property.filter_equals(Date.today)
211
+ .ascending(@db_date_property)
212
+ @today_tasks = @db.query_database(query).map { |tp| Task.new tp, self }
213
+ end
214
+
215
+ def update_today_tasks
216
+ @today_inner_frame&.destroy
217
+ @today_inner_frame = TkFrame.new(@today_outer_frame).pack
218
+ @today_tasks.sort! { |a, b| a.start_time_str <=> b.start_time_str }
219
+ @today_tasks.each_with_index { |task, i| task.view_task @today_inner_frame, i }
220
+ uc = @unfinished_tasks.count
221
+ TkButton.new(@today_inner_frame, text: "Add unfinished #{uc} tasks", command: -> { add_unfinished_tasks })
222
+ .grid(row: @today_tasks.count, column: 0) if uc.positive?
223
+ end
224
+
225
+ def load_someday_tasks
226
+ query = @db_date_property.filter_is_empty
227
+ .and(@db_finish_property.filter_does_not_equal(@conf.fpv))
228
+ unless @conf.ppd.empty?
229
+ ppd_p = @db.properties[@conf.ppd]
230
+ query_is_empty = ppd_p.filter_is_empty another_type: "number"
231
+ query_equals_1 = ppd_p.filter_equals 1, another_type: "number"
232
+ query.and(query_is_empty.or(query_equals_1))
233
+ end
234
+ @someday_tasks = @db.query_database(query).map { |tp| Task.new tp, self }
235
+ end
236
+
237
+ def update_someday_tasks
238
+ @someday_inner_frame&.destroy
239
+ @someday_inner_frame = TkFrame.new(@someday_outer_frame).pack
240
+ @someday_tasks.each_with_index { |task, i| task.view_task @someday_inner_frame, i, false }
241
+ end
242
+
243
+ def add_someday_task
244
+ task_name = @new_today_task_val.value
245
+ if !@conf.bbn.empty? && task_name.include?("|")
246
+ previous_id = nil
247
+ task_name.split("|").each do |title|
248
+ page = @db.create_child_page do |_, pp|
249
+ pp[@conf.tpn] << title
250
+ pp[@conf.bbn].relation = previous_id if previous_id
251
+ end
252
+ previous_id = page.id
253
+ end
254
+ @new_today_task_val.value = ""
255
+ reload
256
+ else
257
+ tp = @db.create_child_page do |_, pp|
258
+ pp[@conf.tpn] << task_name
259
+ end
260
+ @new_today_task_val.value = ""
261
+ @someday_tasks << Task.new(tp, self)
262
+ update_someday_tasks
263
+ end
264
+ end
265
+
266
+ def add_unfinished_tasks
267
+ @unfinished_tasks.each do |task|
268
+ task.time_recording true
269
+ end
270
+ @unfinished_tasks = []
271
+ update_today_tasks
272
+ end
273
+
274
+ def move_to_today(task)
275
+ @someday_tasks.delete task
276
+ @today_tasks << task
277
+ update_today_tasks
278
+ update_someday_tasks
279
+ end
280
+ end
281
+
282
+ @task_conf = TaskConf.new CONF_FILE_NAME, ARGV.first == "-c"
283
+ @task_cache = TaskCache.new @task_conf
284
+ Tk.mainloop
@@ -22,10 +22,11 @@ module NotionRubyMapping
22
22
  @notion_token = nil
23
23
  @wait = 0.3333
24
24
  @debug = false
25
+ @use_cache = true
25
26
  end
26
27
  attr_reader :object_hash
27
28
  attr_writer :client # for test only
28
- attr_accessor :notion_token, :wait, :debug
29
+ attr_accessor :notion_token, :wait, :debug, :use_cache
29
30
 
30
31
  # @param [String] block_id
31
32
  # @return [String (frozen)] block_path
@@ -175,10 +176,12 @@ module NotionRubyMapping
175
176
  # @return [NotionRubyMapping::Base]
176
177
  def object_for_key(id)
177
178
  key = hex_id(id)
178
- return @object_hash[key] if @object_hash.key? key
179
+ return @object_hash[key] if @use_cache && @object_hash.key?(key)
179
180
 
180
181
  json = yield(@client)
181
- @object_hash[key] = Base.create_from_json json
182
+ ans = Base.create_from_json json
183
+ @object_hash[key] = ans if @use_cache
184
+ ans
182
185
  end
183
186
 
184
187
  # @param [String] id page_id (with or without "-")
@@ -24,6 +24,17 @@ module NotionRubyMapping
24
24
  @json["end"]
25
25
  end
26
26
 
27
+ def end_date_obj
28
+ assert_page_property __method__
29
+ jet = @json["end"]
30
+ case jet
31
+ when String
32
+ jet.include?("T") ? Time.parse(jet) : Date.parse(jet)
33
+ else
34
+ jet
35
+ end
36
+ end
37
+
27
38
  # @param [Date, Time, DateTime, String] edt
28
39
  # @see https://www.notion.so/hkob/DateProperty-c6e815c060cb430889dbb33b697f00c6#944c02096101429084527c22155683bf
29
40
  def end_date=(edt)
@@ -41,6 +52,17 @@ module NotionRubyMapping
41
52
  @json["start"]
42
53
  end
43
54
 
55
+ def start_date_obj
56
+ assert_page_property __method__
57
+ jst = @json["start"]
58
+ case jst
59
+ when String
60
+ jst.include?("T") ? Time.parse(jst) : Date.parse(jst)
61
+ else
62
+ jst
63
+ end
64
+ end
65
+
44
66
  # @param [Date, Time, DateTime, String] sdt
45
67
  # @see https://www.notion.so/hkob/DateProperty-c6e815c060cb430889dbb33b697f00c6#4f5931f1588a43f7857af8ab2d73df74
46
68
  def start_date=(sdt)
@@ -24,7 +24,7 @@ module NotionRubyMapping
24
24
  :last_edited_by, :last_edited_time, :multi_select, :multi_select=, :multi_select_names, :number,
25
25
  :number=, :people, :people=, :phone_number, :phone_number=, :property_values_json, :relation=,
26
26
  :rollup, :start_date, :start_date=, :time_zone, :time_zone=, :select, :select=, :select_name, :url,
27
- :url=
27
+ :url=, :start_date_obj, :end_date_obj
28
28
 
29
29
  ## Database property only methods
30
30
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NotionRubyMapping
4
- VERSION = "0.7.4"
4
+ VERSION = "0.7.5"
5
5
  NOTION_VERSION = "2022-06-28"
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: notion_ruby_mapping
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.4
4
+ version: 0.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroyuki KOBAYASHI
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-09 00:00:00.000000000 Z
11
+ date: 2023-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -143,6 +143,7 @@ executables:
143
143
  - erdToNotionDb.rb
144
144
  - notionErDiagram.rb
145
145
  - notionSitemap.rb
146
+ - notionTimeRecorder.rb
146
147
  extensions: []
147
148
  extra_rdoc_files: []
148
149
  files:
@@ -164,6 +165,7 @@ files:
164
165
  - exe/erdToNotionDb.rb
165
166
  - exe/notionErDiagram.rb
166
167
  - exe/notionSitemap.rb
168
+ - exe/notionTimeRecorder.rb
167
169
  - images/post_set_icon.png
168
170
  - images/pre_set_icon.png
169
171
  - images/serial_number.png
@@ -276,7 +278,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
276
278
  - !ruby/object:Gem::Version
277
279
  version: '0'
278
280
  requirements: []
279
- rubygems_version: 3.4.6
281
+ rubygems_version: 3.4.7
280
282
  signing_key:
281
283
  specification_version: 4
282
284
  summary: Notion Ruby mapping tool