serJD commited on
Commit
51ac4a4
·
verified ·
1 Parent(s): 4fa6e5a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +278 -226
app.py CHANGED
@@ -5,14 +5,12 @@
5
  import gradio as gr
6
 
7
  import os
8
-
 
 
9
  import requests
 
10
 
11
- from specklepy.api.client import SpeckleClient
12
- from specklepy.api.credentials import get_default_account, get_local_accounts
13
- from specklepy.transports.server import ServerTransport
14
- from specklepy.api import operations
15
- from specklepy.objects.geometry import Polyline, Point
16
 
17
  from huggingface_hub import webhook_endpoint, WebhookPayload
18
  from fastapi import Request
@@ -21,221 +19,233 @@ import requests
21
  import datetime
22
  import json
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- # dictionary that collects tags that can be added to commit messages.
26
- # key -> column name in notion
27
- # value -> possible values
28
- tag_dict = {"status-message":["WIP", "ReviewNeeded", "Final"]}
29
 
 
 
 
 
 
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
 
 
 
32
 
33
- # tag part seperator -> #+ , other_tags
 
 
34
 
35
- def extract_branch_info(stream_id, server_url=None, token=None):
36
- if server_url and token:
37
- client = SpeckleClient(host=server_url)
38
- client.authenticate_with_token(token=token)
39
 
 
 
 
40
 
41
- branches = client.branch.list(stream_id, 100)
 
 
42
 
43
- branch_info = []
 
 
 
44
 
45
- for branch in branches:
46
- print (branch.name)
47
- branch_data = {
48
- "Name": branch.name,
49
- "description": branch.description,
50
- "url": f"{server_url}/streams/{stream_id}/branches/{branch.name.replace('/', '%2F').replace('+', '%2B')}"
51
-
52
- }
53
 
54
- # Determine sub-variant
55
- #if branch.name.startswith(("template_geometry", "graph_geometry")):
56
- if '+' in branch.name:
57
- slash_index = branch.name.rfind('/')
58
- plus_index = branch.name.find('+', slash_index)
59
- sub_variant = branch.name[slash_index + 1:plus_index]
60
- else:
61
- sub_variant = "default"
62
- branch_data["sub-variant"] = sub_variant
63
 
64
- # Get commits for the branch
65
-
66
- #try:
67
- commits = client.branch.get(stream_id, branch.name).commits.items
68
- if commits:
69
- latest_commit = commits[0]
70
- branch_data["updated"] = latest_commit.createdAt
71
- branch_data["commit_url"] = f"{server_url}streams/{stream_id}/commits/{latest_commit.id}"
72
- branch_data["commit_message"] = latest_commit.message
73
- branch_data["author"] = latest_commit.authorName
74
- # Check if the commit message contains '#+' and then extract tags
75
- if '#+' in latest_commit.message:
76
- tags_part = latest_commit.message.split("#+")[1]
77
- branch_data["status-message"] = [tg for tg in tag_dict["status-message"] if tg in tags_part]
78
- else:
79
- branch_data["status-message"] = []
80
- #except Exception as e:
81
- # print(f"Error fetching commits for branch {branch.name}: {str(e)}")
82
-
83
- branch_info.append(branch_data)
84
-
85
- return branch_info
86
-
87
-
88
- def update_select_options(database_id, headers, branch_names):
89
- update_payload = {
90
- "properties": {
91
- "depends-on": {
92
- "multi_select": {
93
- "options": [{"name": name} for name in branch_names]
94
- }
95
- }
96
- }
97
- }
98
- response = requests.patch(f"https://api.notion.com/v1/databases/{database_id}", headers=headers, json=update_payload)
99
- response.raise_for_status()
100
-
101
- def sync_to_notion(token, database_id, branch_data):
102
- base_url = "https://api.notion.com/v1"
103
- headers = {
104
- "Authorization": f"Bearer {token}",
105
- "Notion-Version": "2022-06-28",
106
- "Content-Type": "application/json"
107
- }
108
 
109
- # Extract all branch names for the "depends-on" options
110
- branch_names = [branch['Name'] for branch in branch_data]
111
- # Update the "depends-on" multi-select options to match branch names
112
- update_select_options(database_id, headers, branch_names)
113
-
114
- try:
115
 
116
-
 
 
117
 
118
- # Fetch existing data from Notion database
119
- response = requests.post(f"{base_url}/databases/{database_id}/query", headers=headers)
120
- response.raise_for_status()
121
- pages = response.json().get('results', [])
122
-
123
- # Create a dictionary for the latest update time of each branch
124
- branch_details = {branch['Name']: {'updated': branch.get('updated', ''), 'commit_message': branch.get('commit_message', '')} for branch in branch_data}
125
 
 
 
 
126
 
127
- # Status color mapping
128
- status_colors = {
129
- "outdated": "red",
130
- "up-to-date": "green",
131
- "empty": "gray"
132
- }
133
 
134
- # Process each branch and update or create Notion rows
135
-
136
- print("branchData", branch_data)
137
- for branch in branch_data:
138
- # Find the corresponding page in Notion
139
- branch_update_time = branch_details.get(branch['Name'], {}).get('updated', '')
140
-
141
- page_id = None
142
- existing_depends_on = []
143
- for page in pages:
144
- notion_name = page['properties']['Name']['title'][0]['text']['content'] if page['properties']['Name']['title'] else ''
145
- if notion_name == branch['Name']:
146
- page_id = page['id']
147
- # Retain the existing value of "depends-on"
148
- existing_depends_on = [dep['name'] for dep in page['properties'].get('depends-on', {}).get('multi_select', [])]
149
- break
150
-
151
- # Determine status based on dependencies
152
- status_tag = "up-to-date" # Default status
153
- for dependency_name in existing_depends_on:
154
- dependency_info = branch_details.get(dependency_name, {})
155
- branch_update_time = branch_details.get(branch['Name'], {}).get('updated', '')
156
-
157
- # Check if the dependency is more recent and if its commit message does not contain 'isConnected'
158
- if dependency_info.get('updated', '') > branch_update_time and "isConnected" not in dependency_info.get('commit_message', ''):
159
- status_tag = "outdated"
160
- break
161
-
162
- # If there's no update information, set status to 'empty'
163
- if not branch_update_time:
164
- status_tag = "empty"
165
-
166
- # Prepare data for updating or creating a page
167
- print (branch.get("url", ""))
168
- updated_value = branch.get("updated")
169
-
170
- if isinstance(updated_value, datetime.datetime): # Use datetime.datetime here
171
- updated_isoformat = updated_value.isoformat()
172
- else:
173
- updated_isoformat = datetime.datetime.now().isoformat() # Use datetime.datetime.now() here
174
- # Prepare status-message tags for multi-select
175
- status_messages = branch.get("status-message", [])
176
- status_message_data = [{"name": sm} for sm in status_messages]
177
-
178
- url_clean = branch.get("url", "")
179
- url_clean = url_clean.replace("xyz//","xyz/")
180
- page_data = {
181
- "properties": {
182
- "Name": {"title": [{"text": {"content": branch['Name']}}]},
183
- "status-tag": {"select": {"name": status_tag}}, # Assuming 'select' type
184
- "status": {"rich_text": [{"text": {"content": "Status: " + status_tag}}]},
185
- "url": {"url": url_clean},
186
- "updated": {"date": {"start": updated_isoformat}},
187
- "description": {"rich_text": [{"text": {"content": str(branch.get("description", ""))}}]},
188
- "sub-variant": {"rich_text": [{"text": {"content": branch.get("sub-variant", "")}}]},
189
- "author": {"rich_text": [{"text": {"content": branch.get("author", "")}}]},
190
- "commit_message": {"rich_text": [{"text": {"content": branch.get("commit_message", "")}}]},
191
- "depends-on": {"multi_select": [{"name": d} for d in existing_depends_on]},
192
- "status-message": {"multi_select": status_message_data}
193
- }
194
- }
195
-
196
-
197
 
198
- # Update an existing page or create a new one
199
- if page_id:
200
- update_url = f"{base_url}/pages/{page_id}"
201
- response = requests.patch(update_url, headers=headers, data=json.dumps(page_data))
202
- else:
203
- create_page_data = {
204
- "parent": {"database_id": database_id},
205
- **page_data
206
- }
207
- response = requests.post(f"{base_url}/pages", headers=headers, data=json.dumps(create_page_data))
208
-
209
- response.raise_for_status()
210
-
211
- print("Data synced to Notion successfully.")
212
-
213
- except requests.exceptions.HTTPError as errh:
214
- print("Http Error:", errh)
215
- except requests.exceptions.ConnectionError as errc:
216
- print("Error Connecting:", errc)
217
- except requests.exceptions.Timeout as errt:
218
- print("Timeout Error:", errt)
219
- except requests.exceptions.RequestException as err:
220
- print("Something went wrong", err)
221
 
222
-
 
 
 
223
 
 
 
 
224
 
 
 
 
 
 
 
 
 
225
 
 
226
 
227
- # Predefined dictionaries of streams to update
228
- streams = {
229
- "2B_100_batch": {
230
- "stream": "287b605243",
231
- "notionDB": '402d60c9c1ef4980a3d85c5a4f4a0c97'
232
- },
233
- "2B_U100_batch": {
234
- "stream": "ebcfc50abe",
235
- "notionDB": '00c3a26a119f487fa028c1ed404f22ba'
 
 
 
 
 
 
 
 
236
  }
237
- }
238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  # Function to run on button click
240
  @webhook_endpoint # Define a unique endpoint URL
241
  async def update_streams(request: Request):
@@ -250,40 +260,82 @@ async def update_streams(request: Request):
250
  speckle_token = os.environ.get("SPECKLE_TOKEN")
251
  notion_token = os.environ.get("NOTION_TOKEN")
252
 
253
- #client = SpeckleClient(host="https://speckle.xyz")
254
- #client.authenticate_with_token(token=speckle_token)
 
 
 
 
 
 
 
255
 
256
 
257
 
258
- if 'payload' in payload and 'stream' in payload['payload']:
259
- stream_info = payload['payload']['stream']
260
- if 'name' in stream_info:
261
- stream_name = stream_info['name']
262
- print("update dat for: " + stream_name)
263
- # retrieve specific stream
264
- stream_id = streams[stream_name]["stream"]
265
- notion_db = streams[stream_name]["notionDB"]
266
- branch_data = extract_branch_info(stream_id, server_url="https://speckle.xyz/", token=speckle_token)
267
- sync_to_notion(notion_token, notion_db, branch_data)
268
- else:
269
- print("updating data for all streams")
270
- for key, value in streams.items():
271
- stream_id = value["stream"]
272
- notion_db = value["notionDB"]
273
 
274
- branch_data = extract_branch_info(stream_id, server_url="https://speckle.xyz/", token=speckle_token)
275
- sync_to_notion(notion_token, notion_db, branch_data)
 
 
 
 
276
 
277
- return "All streams updated successfully!"
278
 
279
- """
280
- # Create Gradio interface
281
- iface = gr.Interface(
282
- fn=update_streams,
283
- inputs=gr.components.Button(value="Update Streams"),
284
- outputs="text",
285
- )
286
-
287
- # Launch the app
288
- iface.launch()
289
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  import gradio as gr
6
 
7
  import os
8
+ import sys
9
+ import time
10
+ import copy
11
  import requests
12
+ from notion_client import Client
13
 
 
 
 
 
 
14
 
15
  from huggingface_hub import webhook_endpoint, WebhookPayload
16
  from fastapi import Request
 
19
  import datetime
20
  import json
21
 
22
+ def get_database_properties_overview(database_pages):
23
+ # Iterate through the results (each page corresponds to a row in the database)
24
+ for page in database_pages:
25
+ print(f"Page ID: {page['id']}")
26
+
27
+ # Print the name and type of each property in this page
28
+ for prop_name, prop_data in page['properties'].items():
29
+ prop_type = prop_data['type']
30
+ print(f"Property Name: {prop_name}, Property Type: {prop_type}")
31
+ break
32
+ # query full database
33
+ def fetch_all_database_pages(client, database_id):
34
+ """
35
+ Fetches all pages from a specified Notion database.
36
+
37
+ :param client: Initialized Notion client.
38
+ :param database_id: The ID of the Notion database to query.
39
+ :return: A list containing all pages from the database.
40
+ """
41
+ start_cursor = None
42
+ all_pages = []
43
+
44
+ while True:
45
+ response = client.databases.query(
46
+ **{
47
+ "database_id": database_id,
48
+ "start_cursor": start_cursor
49
+ }
50
+ )
51
 
52
+ all_pages.extend(response['results'])
 
 
 
53
 
54
+ # Check if there's more data to fetch
55
+ if response['has_more']:
56
+ start_cursor = response['next_cursor']
57
+ else:
58
+ break
59
 
60
+ return all_pages
61
+
62
+ def get_property_value(page, property_name):
63
+ """
64
+ Extracts the value from a specific property in a Notion page based on its type.
65
+ :param page: The Notion page data as retrieved from the API.
66
+ :param property_name: The name of the property whose value is to be fetched.
67
+ :return: The value or values contained in the specified property, depending on type.
68
+ """
69
+ # Check if the property exists in the page
70
+ if property_name not in page['properties']:
71
+ return None # or raise an error if you prefer
72
+
73
+ property_data = page['properties'][property_name]
74
+ prop_type = property_data['type']
75
+
76
+ # Handle 'title' and 'rich_text' types
77
+ if prop_type in ['title', 'rich_text']:
78
+ return ''.join(text_block['text']['content'] for text_block in property_data[prop_type])
79
+
80
+ # Handle 'number' type
81
+ elif prop_type == 'number':
82
+ return property_data[prop_type]
83
+
84
+ # Handle 'select' type
85
+ elif prop_type == 'select':
86
+ return property_data[prop_type]['name'] if property_data[prop_type] else None
87
+
88
+ # Handle 'multi_select' type
89
+ elif prop_type == 'multi_select':
90
+ return [option['name'] for option in property_data[prop_type]]
91
+
92
+ # Handle 'date' type
93
+ elif prop_type == 'date':
94
+ if property_data[prop_type]['end']:
95
+ return (property_data[prop_type]['start'], property_data[prop_type]['end'])
96
+ else:
97
+ return property_data[prop_type]['start']
98
 
99
+ # Handle 'relation' type
100
+ elif prop_type == 'relation':
101
+ return [relation['id'] for relation in property_data[prop_type]]
102
 
103
+ # Handle 'people' type
104
+ elif prop_type == 'people':
105
+ return [person['name'] for person in property_data[prop_type] if 'name' in person]
106
 
107
+ # Add more handlers as needed for other property types
 
 
 
108
 
109
+ else:
110
+ # Return None or raise an error for unsupported property types
111
+ return None
112
 
113
+ def replace_property_value(page, property_name, new_value):
114
+ """
115
+ Replaces the value of a specified property in a Notion page object.
116
 
117
+ :param page: The Notion page object.
118
+ :param property_name: The name of the property to replace.
119
+ :param new_value: The new value to set for the property.
120
+ """
121
 
122
+ if property_name not in page['properties']:
123
+ raise ValueError(f"Property '{property_name}' not found in the page.")
 
 
 
 
 
 
124
 
125
+ prop_type = page['properties'][property_name]['type']
 
 
 
 
 
 
 
 
126
 
127
+ # Handle 'rich_text' and 'title' types
128
+ if prop_type in ['rich_text', 'title']:
129
+ page['properties'][property_name][prop_type] = [{'text': {'content': new_value}}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
+ # Handle 'number' type
132
+ elif prop_type == 'number':
133
+ page['properties'][property_name][prop_type] = new_value
 
 
 
134
 
135
+ # Handle 'select' type
136
+ elif prop_type == 'select':
137
+ page['properties'][property_name][prop_type] = {'name': new_value}
138
 
139
+ # Handle 'multi_select' type (assuming new_value is a list of strings)
140
+ elif prop_type == 'multi_select':
141
+ page['properties'][property_name][prop_type] = [{'name': val} for val in new_value]
 
 
 
 
142
 
143
+ # Handle 'date' type
144
+ elif prop_type == 'date':
145
+ page['properties'][property_name][prop_type] = {'start': new_value} # Assuming new_value is a date string
146
 
147
+ # Handle 'checkbox' type
148
+ elif prop_type == 'checkbox':
149
+ page['properties'][property_name][prop_type] = new_value # Assuming new_value is a boolean
 
 
 
150
 
151
+ # Handle 'url' type
152
+ elif prop_type == 'url':
153
+ page['properties'][property_name][prop_type] = new_value # Assuming new_value is a valid URL string
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
+ # Handle 'email' type
156
+ elif prop_type == 'email':
157
+ page['properties'][property_name][prop_type] = new_value # Assuming new_value is a valid email string
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
+ # Add more handlers for other types as needed
160
+
161
+ else:
162
+ raise NotImplementedError(f"Property type '{prop_type}' is not supported in this function.")
163
 
164
+ def remove_property(page, property_name):
165
+ """
166
+ Removes a specified property from a Notion page object.
167
 
168
+ :param page: The Notion page object.
169
+ :param property_name: The name of the property to remove.
170
+ :return: The updated Notion page object.
171
+ """
172
+ if property_name in page['properties']:
173
+ del page['properties'][property_name]
174
+ else:
175
+ raise ValueError(f"Property '{property_name}' not found in the page.")
176
 
177
+ return page
178
 
179
+
180
+ def check_and_update_or_create_page(notion, page_data, target_database_id, title_property_name):
181
+ """
182
+ Checks if a page with the given title exists in the target database.
183
+ If it does, updates the page; if not, creates a new page.
184
+
185
+ :param notion: Notion client instance.
186
+ :param page_data: Data for the page to create or update.
187
+ :param target_database_id: ID of the target database.
188
+ :param title_property_name: The name of the title property to check.
189
+ """
190
+ # Query the target database for a page with the same >> title <<
191
+ query_filter = {
192
+ "property": title_property_name,
193
+ "title": {
194
+ "equals": page_data['properties'][title_property_name]['title'][0]['text']['content']
195
+ }
196
  }
 
197
 
198
+ response = notion.databases.query(database_id=target_database_id, filter=query_filter)
199
+ existing_pages = response.get('results', [])
200
+
201
+ if existing_pages:
202
+ # Page already exists, update it
203
+ page_id = existing_pages[0]['id']
204
+ print(page_data['properties'])
205
+ notion.pages.update(page_id=page_id, properties=page_data['properties'])
206
+
207
+ else:
208
+ # Page does not exist, create it
209
+ notion.pages.create(parent={"database_id": target_database_id}, properties=page_data['properties'])
210
+
211
+ def get_page_by_id(notion_db_pages, page_id):
212
+ for pg in notion_db_pages:
213
+ if pg["id"] == page_id:
214
+ return pg
215
+
216
+ def reset_database(notion, database_id):
217
+ """
218
+ Resets a Notion database by archiving all its pages.
219
+
220
+ Parameters:
221
+ notion (Client): The Notion client instance.
222
+ database_id (str): The ID of the database to reset.
223
+ """
224
+
225
+ def retrieve_all_pages():
226
+ has_more = True
227
+ start_cursor = None
228
+ pages = []
229
+
230
+ while has_more:
231
+ response = notion.databases.query(
232
+ **{"database_id": database_id, "start_cursor": start_cursor}
233
+ )
234
+ pages.extend(response["results"])
235
+ has_more = response["has_more"]
236
+ start_cursor = response.get("next_cursor")
237
+
238
+ return pages
239
+
240
+ def delete_page(page_id):
241
+ notion.pages.update(page_id, archived=True)
242
+
243
+ pages = retrieve_all_pages()
244
+ for page in pages:
245
+ delete_page(page["id"])
246
+
247
+ print(f"Reset of database {database_id} completed.")
248
+
249
  # Function to run on button click
250
  @webhook_endpoint # Define a unique endpoint URL
251
  async def update_streams(request: Request):
 
260
  speckle_token = os.environ.get("SPECKLE_TOKEN")
261
  notion_token = os.environ.get("NOTION_TOKEN")
262
 
263
+ if continueFlag:
264
+ name_mapper = {}
265
+ name_mapperM = {}
266
+ for page in lu_name_db["results"]:
267
+ oriName = get_property_value(page, "name")
268
+ shortName = get_property_value(page, "nameShort")
269
+ medName = get_property_value(page, "nameMedium")
270
+ name_mapper[oriName] = shortName
271
+ name_mapperM[oriName] = medName
272
 
273
 
274
 
275
+ # Iterate through the results (each page corresponds to a row in the database)
276
+ for page in database_pages:
 
 
 
 
 
 
 
 
 
 
 
 
 
277
 
278
+ #check speckleAnalysisName
279
+ speckName = get_property_value(page, "speckleName")
280
+ shortName = get_property_value(page, "nameShort")
281
+ longName = get_property_value(page, "nameLong")
282
+ print(shortName)
283
+ print(longName)
284
 
 
285
 
286
+ subAttributes = get_property_value(page, "level_4")
287
+
288
+ subAttributeFlag = False
289
+ if len(subAttributes)>1:
290
+ if subAttributes[0] != 'NA':
291
+ subAttributeFlag = True
292
+ for subAttr in subAttributes:
293
+ # construct new page (speckleName, Name, longName, shortName, remove level_4)
294
+ new_page = copy.deepcopy(page)
295
+ speckName_full = speckName+subAttr
296
+ if "#+" in shortName:
297
+ shortestName = name_mapper.get(subAttr,subAttr)
298
+ mediumName = name_mapperM.get(subAttr,subAttr)
299
+ print("shortestName", shortestName, subAttr)
300
+ shortName_full = shortName.replace("#+", shortestName)
301
+ shortName_full.replace("DRT", "ART")
302
+ #update short name
303
+ replace_property_value(new_page, "nameShort", shortName_full )
304
+
305
+ if "#+" in longName:
306
+ longName_full = longName.replace("#+", "::" +mediumName)
307
+ longName_full = longName_full.replace(" ::", "::")
308
+ longName_full = longName_full.replace(":: ", "::")
309
+ longName_full.replace("DRT", "ART")
310
+ #update long name
311
+ replace_property_value(new_page, "nameLong", longName_full )
312
+
313
+
314
+
315
+ #update speckle name (-> as title column)
316
+ replace_property_value(new_page, "name", speckName_full)
317
+ # remove level_4 and speckleAnalysisName
318
+ new_page = remove_property(new_page, "level_4")
319
+ new_page = remove_property(new_page, "speckleName")
320
+ new_page = remove_property(new_page, "Items")
321
+
322
+ # update target database in notion
323
+ check_and_update_or_create_page(notion, new_page, target_db, "name")
324
+
325
+
326
+
327
+ if subAttributeFlag == False:
328
+ # forward page
329
+ new_page = copy.deepcopy(page)
330
+ replace_property_value(new_page, "name", speckName)
331
+ new_page = remove_property(new_page, "level_4")
332
+ new_page = remove_property(new_page, "speckleName")
333
+ new_page = remove_property(new_page, "Items")
334
+
335
+ # update target database in notion
336
+ print(get_property_value(new_page, "nameLong"))
337
+ check_and_update_or_create_page(notion, new_page, target_db, "name")
338
+
339
+
340
+
341
+ return "All streams updated successfully!"