Skip to content

Commit 974dcb8

Browse files
authored
feat: Cleanup Review's importer | NPG-7782 (#557)
# Description Cleanup review's importer logic, updated configuration process, load config from file
1 parent 97a6074 commit 974dcb8

File tree

7 files changed

+57
-88
lines changed

7 files changed

+57
-88
lines changed

src/event-db/stage_data/dev/00002_testfund_ideascale_params.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ INSERT INTO config (id, id2, id3, value) VALUES (
1414
"Question 3": "Auditability"
1515
},
1616
"stage_ids": [4684, 4685, 4686],
17+
"anonymize_start_id": 5000,
1718
"proposals": {
1819
"field_mappings": {
1920
"proposer_url": ["relevant_link_1", "website__github_repository__or_any_other_relevant_link__", "relevant_link_3"],

utilities/ideascale-importer/Earthfile

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,9 @@ docker:
7676
test:
7777
FROM +build
7878

79-
COPY ../../src/event-db+docker-compose/docker-compose.yml docker-compose.yml
80-
WITH DOCKER \
81-
--compose docker-compose.yml \
82-
--pull postgres:14 \
83-
--load migrations:latest=(../../containers/event-db-migrations+docker --data=test) \
84-
--service migrations \
85-
--allow-privileged
86-
RUN --no-cache \
87-
--secret IDEASCALE_EMAIL \
88-
--secret IDEASCALE_PASSWORD \
89-
--secret IDEASCALE_API_TOKEN \
90-
EVENTDB_URL="postgres://catalyst-event-dev:CHANGE_ME@localhost/CatalystEventDev" \
91-
IDEASCALE_API_URL="https://temp-cardano-sandbox.ideascale.com" \
92-
poetry run pytest
93-
END
79+
RUN --no-cache \
80+
--secret IDEASCALE_EMAIL \
81+
--secret IDEASCALE_PASSWORD \
82+
--secret IDEASCALE_API_TOKEN \
83+
IDEASCALE_API_URL="https://temp-cardano-sandbox.ideascale.com" \
84+
poetry run pytest

utilities/ideascale-importer/ideascale_importer/cli/reviews.py

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ def import_reviews(
1616
envvar="IDEASCALE_API_URL",
1717
help="IdeaScale API URL",
1818
),
19-
database_url: str = typer.Option(
20-
...,
21-
envvar="EVENTDB_URL",
22-
help="Postgres database URL"
23-
),
2419
email: str = typer.Option(
2520
...,
2621
envvar="IDEASCALE_EMAIL",
@@ -31,15 +26,15 @@ def import_reviews(
3126
envvar="IDEASCALE_PASSWORD",
3227
help="Ideascale user's password (needs admin access)",
3328
),
34-
event_id: int = typer.Option(
35-
...,
36-
help="Database row id of the event which data will be imported",
37-
),
3829
api_token: str = typer.Option(
3930
...,
4031
envvar="IDEASCALE_API_TOKEN",
4132
help="IdeaScale API token"
4233
),
34+
config_path: str = typer.Option(
35+
...,
36+
help="config file"
37+
),
4338
allocations_path: str = typer.Option(
4439
...,
4540
help="allocations file"
@@ -65,11 +60,10 @@ def import_reviews(
6560
async def inner():
6661
importer = ReviewsManager(
6762
ideascale_url=ideascale_url,
68-
database_url=database_url,
6963
email=email,
7064
password=password,
7165
api_token=api_token,
72-
event_id=event_id,
66+
config_path=config_path
7367
)
7468

7569
try:
@@ -92,30 +86,15 @@ def prepare_allocations(
9286
envvar="IDEASCALE_API_URL",
9387
help="IdeaScale API URL",
9488
),
95-
database_url: str = typer.Option(
96-
...,
97-
envvar="EVENTDB_URL",
98-
help="Postgres database URL"
99-
),
100-
email: str = typer.Option(
101-
...,
102-
envvar="IDEASCALE_EMAIL",
103-
help="Ideascale user's email address (needs admin access)",
104-
),
105-
password: str = typer.Option(
106-
...,
107-
envvar="IDEASCALE_PASSWORD",
108-
help="Ideascale user's password (needs admin access)",
109-
),
110-
event_id: int = typer.Option(
111-
...,
112-
help="Database row id of the event which data will be imported",
113-
),
11489
api_token: str = typer.Option(
11590
...,
11691
envvar="IDEASCALE_API_TOKEN",
11792
help="IdeaScale API token"
11893
),
94+
config_path: str = typer.Option(
95+
...,
96+
help="config file"
97+
),
11998
pas_path: str = typer.Option(
12099
...,
121100
help="PAs file"
@@ -141,11 +120,8 @@ def prepare_allocations(
141120
async def inner():
142121
importer = ReviewsManager(
143122
ideascale_url=ideascale_url,
144-
database_url=database_url,
145-
email=email,
146-
password=password,
147123
api_token=api_token,
148-
event_id=event_id,
124+
config_path=config_path
149125
)
150126

151127
try:

utilities/ideascale-importer/ideascale_importer/reviews_manager/manager.py

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from typing import List, Dict
55
import pydantic
66
import tempfile
7+
import json
78

89
from ideascale_importer import utils
910
import ideascale_importer.db
@@ -65,44 +66,32 @@ class ReviewsManager:
6566
def __init__(
6667
self,
6768
ideascale_url,
68-
database_url,
69-
email,
70-
password,
71-
event_id,
7269
api_token,
70+
config_path = None,
71+
email = None,
72+
password = None,
7373
):
7474
self.ideascale_url = ideascale_url
75-
self.database_url = database_url
7675
self.email = email
7776
self.password = password
78-
self.event_id = event_id
7977
self.api_token = api_token
78+
self.config_path = config_path
8079

8180
self.frontend_client = None
8281
self.db = None
8382

8483
async def connect(self):
85-
if self.frontend_client is None:
84+
if self.frontend_client is None and (self.email and self.password):
8685
logger.info("Connecting to the Ideascale frontend")
8786
self.frontend_client = FrontendClient(self.ideascale_url)
8887
await self.frontend_client.login(self.email, self.password)
89-
if self.db is None:
90-
logger.info("Connecting to the database")
91-
self.db = await ideascale_importer.db.connect(self.database_url)
9288

9389
async def __load_config(self):
9490
"""Load the configuration setting from the event db."""
9591

96-
logger.info("Loading ideascale config from the event-db")
97-
98-
config = ideascale_importer.db.models.Config(row_id=0, id="ideascale", id2=f"{self.event_id}", id3="", value=None)
99-
res = await ideascale_importer.db.select(self.db, config, cond={
100-
"id": f"= '{config.id}'",
101-
"AND id2": f"= '{config.id2}'"
102-
})
103-
if len(res) == 0:
104-
raise Exception("Cannot find ideascale config in the event-db database")
105-
self.config = Config(**res[0].value)
92+
logger.info(f"Loading ideascale config from {self.config_path}")
93+
config_data = json.load(open(self.config_path))
94+
self.config = Config(**config_data)
10695

10796
async def __download_reviews(self, reviews_output_path: str):
10897
logger.info("Download reviews from Ideascale...")
@@ -113,14 +102,15 @@ async def __download_reviews(self, reviews_output_path: str):
113102
async def __prepare_allocations(self, pas_path: str, output_path: str):
114103
logger.info("Prepare allocations for proposal's reviews...")
115104

116-
self.allocations = await allocate(
117-
nr_allocations=self.config.nr_allocations,
105+
await allocate(
106+
nr_allocations=self.config.allocations_number,
118107
pas_path=pas_path,
119108
ideascale_api_key=self.api_token,
120109
ideascale_api_url=self.ideascale_url,
121110
stage_ids=self.config.stage_ids,
122111
challenges_group_id=self.config.campaign_group_id,
123112
group_id=self.config.group_id,
113+
anonymize_start_id=self.config.anonymize_start_id,
124114
output_path=output_path,
125115
)
126116

@@ -133,7 +123,7 @@ async def __prepare_reviews(self, allocations_path: str, output_path: str):
133123
allocation_path=allocations_path,
134124
challenges_group_id=self.config.campaign_group_id,
135125
questions=self.config.questions,
136-
fund=self.event_id,
126+
fund=self.config.event_id,
137127
output_path=output_path
138128
)
139129

@@ -159,14 +149,17 @@ async def import_reviews_run(self, allocations_path: str, output_path: str):
159149
reviews_dir.cleanup()
160150

161151
async def close(self):
162-
await self.frontend_client.close()
152+
if self.frontend_client:
153+
await self.frontend_client.close()
163154

164155
class Config(pydantic.BaseModel):
165156
"""Represents the available configuration fields."""
166157

158+
event_id: int
167159
group_id: int
168160
campaign_group_id: int
169161
review_stage_ids: List[int]
170162
stage_ids: List[int]
171-
nr_allocations: List[int]
163+
allocations_number: List[int]
172164
questions: Dict[str, str]
165+
anonymize_start_id: int

utilities/ideascale-importer/ideascale_importer/reviews_manager/processing/prepare.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ async def allocate(
1919
stage_ids: List[int],
2020
nr_allocations: List[int],
2121
output_path: str,
22-
anonymize_start_id: int = 5000,
22+
anonymize_start_id: int,
2323
seed: int = 7,
2424
):
2525
"""Run the allocator check."""
@@ -34,17 +34,13 @@ async def _allocate():
3434
await ideascale.import_com_revs(group_id=group_id, start_id=anonymize_start_id, historic_pas=importer.pas)
3535
allocator.allocate()
3636

37-
# This data is not used by our core system, it is only consumed by Ideascale
37+
allocator.export_allocations(allocator.source.pas, f"{output_path}/allocations-by-pa.xlsx")
38+
groups = allocator.generate_challenges_groups()
39+
for group in groups:
40+
allocator.export_allocations(group["pas"], f"{output_path}/{group['challenge']}.xlsx")
3841

39-
# allocator.export_allocations(allocator.source.pas, f"{output_path}/allocations-by-pa.xlsx")
40-
# groups = allocator.generate_challenges_groups()
41-
# for group in groups:
42-
# allocator.export_allocations(group["pas"], f"{output_path}/{group['challenge']}.xlsx")
43-
44-
file_name = f"{output_path}/allocations.csv"
45-
allocator.export_single_allocations(allocator.allocations, file_name)
42+
allocator.export_single_allocations(allocator.allocations, f"{output_path}/allocations.csv")
4643
allocator.allocation_stats()
47-
return file_name
4844

4945
def nr_allocations_map():
5046
res = {}

utilities/ideascale-importer/ideascale_importer/tests/reviews_test.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,16 @@ def get_env_var(env_var):
1212
@pytest.fixture()
1313
def reviews_manager_mock():
1414
ideascale_url = get_env_var("IDEASCALE_API_URL")
15-
database_url = get_env_var("EVENTDB_URL")
1615
email = get_env_var("IDEASCALE_EMAIL")
1716
password = get_env_var("IDEASCALE_PASSWORD")
18-
event_id = 0
1917
api_token = get_env_var("IDEASCALE_API_TOKEN")
18+
config_path = "./ideascale_importer/tests/test_data/config.json"
2019
return ReviewsManager(
2120
ideascale_url=ideascale_url,
22-
database_url=database_url,
2321
email=email,
2422
password=password,
2523
api_token=api_token,
26-
event_id=event_id,
24+
config_path=config_path
2725
)
2826

2927
@pytest.mark.asyncio
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"event_id": 0,
3+
"group_id": 37429,
4+
"review_stage_ids": [171],
5+
"allocations_number": [1, 1],
6+
"campaign_group_id": 88,
7+
"questions": {
8+
"Question 1": "Impact / Alignment",
9+
"Question 2": "Feasibility",
10+
"Question 3": "Auditability"
11+
},
12+
"stage_ids": [4684, 4685, 4686],
13+
"anonymize_start_id": 5000
14+
}

0 commit comments

Comments
 (0)