Browse Source

Add script to sync people from Aardbei

Maarten van den Berg 5 years ago
parent
commit
29302bc68c
1 changed files with 175 additions and 0 deletions
  1. 175 0
      piket_server/aardbei_sync.py

+ 175 - 0
piket_server/aardbei_sync.py

@@ -0,0 +1,175 @@
1
+from __future__ import annotations
2
+
3
+from typing import List, Dict, Any, Tuple, Optional
4
+from dataclasses import dataclass
5
+import logging
6
+
7
+import requests
8
+
9
+from piket_server import Person, db
10
+
11
+
12
+@dataclass(frozen=True)
13
+class SparseAardbeiPerson:
14
+    full_name: str
15
+    display_name: str
16
+    aardbei_id: int
17
+    is_leader: bool
18
+
19
+    @classmethod
20
+    def from_aardbei_dict(cls, data: Dict[str, Any]) -> SparseAardbeiPerson:
21
+        return cls(
22
+            full_name=data["member"]["person"]["full_name"],
23
+            display_name=data["member"]["display_name"],
24
+            aardbei_id=data["member"]["person"]["id"],
25
+            is_leader=data["member"]["is_leader"],
26
+        )
27
+
28
+
29
+@dataclass(frozen=True)
30
+class AardbeiMatch:
31
+    local: Person
32
+    remote: SparseAardbeiPerson
33
+
34
+
35
+@dataclass(frozen=True)
36
+class AardbeiLink:
37
+    matches: List[AardbeiMatch]
38
+    """People that exist on both sides, but aren't linked in the people table."""
39
+    altered_name: List[AardbeiMatch]
40
+    """People that are already linked but changed one of their names."""
41
+    remote_only: List[SparseAardbeiPerson]
42
+    """People that only exist on the remote."""
43
+
44
+
45
+def get_aardbei_people(token: str) -> List[SparseAardbeiPerson]:
46
+    resp = requests.get(
47
+        "https://aardbei.app/api/groups/0/", headers={"Authorization": f"Group {token}"}
48
+    )
49
+    resp.raise_for_status()
50
+
51
+    members = resp.json()["group"]["members"]
52
+
53
+    return [SparseAardbeiPerson.from_aardbei_dict(x) for x in members]
54
+
55
+
56
+def match_local_aardbei(aardbei_people: List[SparseAardbeiPerson]) -> AardbeiLink:
57
+    matches: List[AardbeiMatch] = []
58
+    altered_name: List[AardbeiMatch] = []
59
+    remote_only: List[SparseAardbeiPerson] = []
60
+
61
+    for aardbei_person in aardbei_people:
62
+        p: Optional[Person] = Person.query.filter_by(
63
+            aardbei_id=aardbei_person.aardbei_id
64
+        ).one_or_none()
65
+
66
+        if p is not None:
67
+            if (
68
+                p.full_name != aardbei_person.full_name
69
+                or p.display_name != aardbei_person.display_name
70
+            ):
71
+                altered_name.append(AardbeiMatch(p, aardbei_person))
72
+
73
+            else:
74
+                logging.info(
75
+                    "OK: %s / %s (L%s/R%s)",
76
+                    p.full_name,
77
+                    p.display_name,
78
+                    p.person_id,
79
+                    p.aardbei_id,
80
+                )
81
+
82
+            continue
83
+
84
+        p = Person.query.filter_by(full_name=aardbei_person.full_name).one_or_none()
85
+
86
+        if p is not None:
87
+            matches.append(AardbeiMatch(p, aardbei_person))
88
+        else:
89
+            remote_only.append(aardbei_person)
90
+
91
+    return AardbeiLink(matches, altered_name, remote_only)
92
+
93
+
94
+def link_matches(matches: List[AardbeiMatch]) -> None:
95
+    for match in matches:
96
+        match.local.aardbei_id = match.remote.aardbei_id
97
+        match.local.display_name = match.remote.display_name
98
+        logging.info(
99
+            "Linking local %s (%s) to remote %s (%s)",
100
+            match.local.full_name,
101
+            match.local.person_id,
102
+            match.remote.display_name,
103
+            match.remote.aardbei_id,
104
+        )
105
+
106
+        db.session.add(match.local)
107
+
108
+
109
+def create_missing(missing: List[SparseAardbeiPerson]) -> None:
110
+    for person in missing:
111
+        pnew = Person(
112
+            full_name=person.full_name,
113
+            display_name=person.display_name,
114
+            aardbei_id=person.aardbei_id,
115
+            active=False,
116
+        )
117
+        logging.info(
118
+            "Creating new person for %s (%s)", person.full_name, person.aardbei_id
119
+        )
120
+        db.session.add(pnew)
121
+
122
+
123
+def update_names(matches: List[AardbeiMatch]) -> None:
124
+    for match in matches:
125
+        p = match.local
126
+        aardbei_person = match.remote
127
+
128
+        changed = False
129
+
130
+        if p.full_name != aardbei_person.full_name:
131
+            logging.info(
132
+                "Updating %s (L%s/R%s) full name %s to %s",
133
+                aardbei_person.full_name,
134
+                p.person_id,
135
+                aardbei_person.aardbei_id,
136
+                p.full_name,
137
+                aardbei_person.full_name,
138
+            )
139
+            p.full_name = aardbei_person.full_name
140
+            changed = True
141
+
142
+        if p.display_name != aardbei_person.display_name:
143
+            logging.info(
144
+                "Updating %s (L%s/R%s) display name %s to %s",
145
+                aardbei_person.full_name,
146
+                p.person_id,
147
+                aardbei_person.aardbei_id,
148
+                p.display_name,
149
+                aardbei_person.display_name,
150
+            )
151
+            p.display_name = aardbei_person.display_name
152
+
153
+            changed = True
154
+
155
+        assert changed, "got match but didn't update anything"
156
+
157
+        db.session.add(p)
158
+
159
+
160
+if __name__ == "__main__":
161
+    logging.basicConfig(level=logging.INFO)
162
+
163
+    token = input("Token: ")
164
+    aardbei_people = get_aardbei_people(token)
165
+    link = match_local_aardbei(aardbei_people)
166
+    link_matches(link.matches)
167
+    create_missing(link.remote_only)
168
+    update_names(link.altered_name)
169
+
170
+    confirm = input("Commit? Y/N")
171
+    if confirm.lower() == "y":
172
+        print("Committing.")
173
+        db.session.commit()
174
+    else:
175
+        print("Not committing.")