Skip to content
This repository was archived by the owner on Mar 12, 2025. It is now read-only.

Commit 0cbfaf8

Browse files
New script to copy group associations from groups api to ubahn
1 parent eb078f9 commit 0cbfaf8

File tree

1 file changed

+282
-0
lines changed

1 file changed

+282
-0
lines changed

update-groups-v2.js

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
/**
2+
* Purpose is same as update-groups.js => To copy groups info from groups
3+
* api to ubahn. However, approach is different:
4+
* - Read all users in ubahn
5+
* - Get their topcoder user ids
6+
* - Use the user ids to get the group associations in groups api
7+
* - Copy the associations into ubahn
8+
*
9+
* Run the script with `node update-groups-v2.js`
10+
*/
11+
const _ = require('lodash')
12+
const config = require('config')
13+
const axios = require('axios')
14+
const m2mAuth = require('tc-core-library-js').auth.m2m
15+
const elasticsearch = require('elasticsearch')
16+
17+
const ubahnM2MConfig = _.pick(config, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME', 'AUTH0_PROXY_SERVER_URL'])
18+
const topcoderM2MConfig = _.pick(config, ['AUTH0_URL', 'AUTH0_TOPCODER_AUDIENCE', 'TOKEN_CACHE_TIME', 'AUTH0_PROXY_SERVER_URL'])
19+
20+
const ubahnM2M = m2mAuth({ ...ubahnM2MConfig, AUTH0_AUDIENCE: ubahnM2MConfig.AUTH0_AUDIENCE })
21+
22+
const topcoderM2M = m2mAuth({ ...topcoderM2MConfig, AUTH0_AUDIENCE: topcoderM2MConfig.AUTH0_TOPCODER_AUDIENCE })
23+
24+
let esClient
25+
26+
async function sleep (ms) {
27+
return new Promise(resolve => setTimeout(resolve, ms))
28+
}
29+
30+
/**
31+
* Get M2M token.
32+
* @returns {Promise<unknown>}
33+
*/
34+
async function getTCM2MToken () {
35+
return topcoderM2M.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET)
36+
}
37+
38+
/**
39+
* Returns m2m token for use with ubahn's apis
40+
*/
41+
async function getUbahnM2Mtoken () {
42+
return ubahnM2M.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET)
43+
}
44+
45+
/**
46+
* Returns all groups associated with the member
47+
* @param {String} memberId The member id
48+
*/
49+
async function getGroupsOfUser (memberId) {
50+
const membershipType = 'user'
51+
const url = `${config.GROUPS_API_URL}`
52+
const perPage = 12
53+
let page = 1
54+
const groups = []
55+
let once = false
56+
57+
const token = await getTCM2MToken()
58+
59+
while (true) {
60+
try {
61+
const res = await axios.get(url, {
62+
params: {
63+
page,
64+
perPage,
65+
memberId,
66+
membershipType
67+
},
68+
headers: {
69+
Authorization: `Bearer ${token}`
70+
}
71+
})
72+
73+
if (!once) {
74+
const total = res.headers['x-total']
75+
console.log(`Discovered ${total} groups...`)
76+
77+
if (total > 0) {
78+
console.log('Fetching all of them...')
79+
}
80+
81+
once = true
82+
}
83+
84+
if (res.data.length > 0) {
85+
groups.push(...res.data)
86+
}
87+
88+
if (res.data.length !== perPage) {
89+
break
90+
}
91+
92+
page += 1
93+
} catch (error) {
94+
console.log(`Error when fetching groups at page ${page} and per page ${perPage} for member ${memberId}`)
95+
console.log(error)
96+
97+
throw error
98+
}
99+
}
100+
101+
return groups
102+
}
103+
104+
/**
105+
* Returns all users in ubahn
106+
*/
107+
async function getAllUbahnUsers () {
108+
const perPage = 12
109+
let page = 1
110+
const users = []
111+
let once = false
112+
113+
const token = await getUbahnM2Mtoken()
114+
115+
while (true) {
116+
try {
117+
const res = await axios.get(config.UBAHN_USERS_API_URL, {
118+
headers: {
119+
Authorization: `Bearer ${token}`
120+
}
121+
})
122+
123+
if (!once) {
124+
const total = res.headers['x-total']
125+
console.log(`Discovered ${total} user(s) in ubahn...`)
126+
127+
if (total > 0) {
128+
console.log('Fetching all of them...')
129+
}
130+
131+
once = true
132+
}
133+
134+
if (res.data.length > 0) {
135+
users.push(...res.data)
136+
}
137+
138+
if (res.data.length !== perPage) {
139+
break
140+
}
141+
142+
page += 1
143+
} catch (error) {
144+
console.log(`Error when fetching users in ubahn at page ${page} and per page ${perPage}`)
145+
console.log(error)
146+
147+
throw error
148+
}
149+
}
150+
151+
return users
152+
}
153+
154+
/**
155+
* Returns the external profile of the user
156+
* @param {String} userId The ubahn user id
157+
*/
158+
async function getExternalProfile (userId) {
159+
const url = `${config.UBAHN_USERS_API_URL}/${userId}/externalProfiles`
160+
const token = await getUbahnM2Mtoken()
161+
try {
162+
const res = await axios.get(url, {
163+
headers: {
164+
Authorization: `Bearer ${token}`
165+
}
166+
})
167+
168+
return res.data
169+
} catch (error) {
170+
console.log(`Error fetching the external profile of user with id ${userId}`)
171+
console.log(error)
172+
173+
throw error
174+
}
175+
}
176+
177+
/**
178+
* Returns the Elasticsearch client
179+
*/
180+
async function getESClient () {
181+
const host = config.ES.HOST
182+
const apiVersion = config.ES.API_VERSION
183+
184+
if (esClient) {
185+
return esClient
186+
}
187+
188+
// AWS ES configuration is different from other providers
189+
if (/.*amazonaws.*/.test(host)) {
190+
try {
191+
esClient = new elasticsearch.Client({
192+
apiVersion,
193+
host,
194+
connectionClass: require('http-aws-es') // eslint-disable-line global-require
195+
})
196+
} catch (error) { console.log(error) }
197+
} else {
198+
esClient = new elasticsearch.Client({
199+
apiVersion,
200+
host
201+
})
202+
}
203+
204+
return esClient
205+
}
206+
207+
/**
208+
* Updates the groups in the user
209+
* @param {String} userId The user id
210+
* @param {Array} groups The array of groups
211+
*/
212+
async function updateGroupsForUser (userId, groups) {
213+
const client = await getESClient()
214+
let user = await client.get({ index: config.get('ES.USER_INDEX'), type: config.get('ES.USER_TYPE'), id: userId })
215+
user = user._source
216+
217+
const propertyName = config.get('ES.USER_GROUP_PROPERTY_NAME')
218+
if (!user[propertyName]) {
219+
user[propertyName] = []
220+
}
221+
222+
let groupsTotal = user[propertyName].concat(groups)
223+
224+
groupsTotal = _.uniqBy(groupsTotal, (g) => g.groupId)
225+
226+
user[propertyName] = groupsTotal
227+
228+
await client.update({
229+
index: config.get('ES.USER_INDEX'),
230+
type: config.get('ES.USER_TYPE'),
231+
id: userId,
232+
body: { doc: user },
233+
refresh: 'wait_for'
234+
})
235+
}
236+
237+
/**
238+
* Main function
239+
*/
240+
async function start () {
241+
// Get all users in ubahn
242+
const users = await getAllUbahnUsers()
243+
const final = {}
244+
245+
for (let i = 0; i < users.length; i++) {
246+
const userId = users[i].id
247+
248+
console.log(`Getting external profile of user with id ${userId}`)
249+
250+
// Get external profiles of the user (to get the tc member ids of the ubahn users)
251+
let externalProfiles = await getExternalProfile(userId)
252+
253+
externalProfiles = _.uniqBy(externalProfiles, (e) => e.externalId)
254+
255+
// Get groups of the user
256+
for (let j = 0; j < externalProfiles.length; j++) {
257+
const memberId = externalProfiles[j].externalId
258+
console.log(`Getting groups of user with id ${memberId}`)
259+
let groups = await getGroupsOfUser(memberId)
260+
groups = groups.map(g => ({ groupId: g.id, name: g.name }))
261+
262+
if (groups.length > 0) {
263+
if (!final[userId]) {
264+
final[userId] = groups
265+
} else {
266+
final[userId] = final[userId].concat(groups)
267+
}
268+
}
269+
}
270+
}
271+
272+
const keys = Object.keys(final)
273+
274+
for (let i = 0; i < keys.length; i++) {
275+
await updateGroupsForUser(keys[i], final[keys[i]])
276+
await sleep()
277+
}
278+
279+
console.log('All groups copied over to ubahn as relevant')
280+
}
281+
282+
start()

0 commit comments

Comments
 (0)