notion_ruby_mapping 0.7.4 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
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