Abhishek Thakur
commited on
Commit
·
bf3d263
1
Parent(s):
7b9d0c2
option to change team name
Browse files- competitions/app.py +24 -0
- competitions/templates/index.html +110 -13
- competitions/utils.py +70 -0
competitions/app.py
CHANGED
@@ -51,6 +51,11 @@ if REQUIREMENTS_FNAME:
|
|
51 |
utils.install_requirements(REQUIREMENTS_FNAME)
|
52 |
|
53 |
|
|
|
|
|
|
|
|
|
|
|
54 |
class User(BaseModel):
|
55 |
user_token: str
|
56 |
|
@@ -193,6 +198,7 @@ async def my_submissions(request: Request, user: User):
|
|
193 |
"submissions": "",
|
194 |
"submission_text": SUBMISSION_TEXT.format(COMP_INFO.submission_limit),
|
195 |
"error": "**Invalid token**",
|
|
|
196 |
}
|
197 |
}
|
198 |
subs = subs.to_dict(orient="records")
|
@@ -204,11 +210,14 @@ async def my_submissions(request: Request, user: User):
|
|
204 |
submission_text = SUBMISSION_TEXT.format(COMP_INFO.submission_limit)
|
205 |
submission_selection_text = SUBMISSION_SELECTION_TEXT.format(COMP_INFO.selection_limit)
|
206 |
|
|
|
|
|
207 |
resp = {
|
208 |
"response": {
|
209 |
"submissions": subs,
|
210 |
"submission_text": submission_text + submission_selection_text,
|
211 |
"error": error,
|
|
|
212 |
}
|
213 |
}
|
214 |
return resp
|
@@ -282,3 +291,18 @@ def update_selected_submissions(request: Request, user_sub: UserSubmissionUpdate
|
|
282 |
}
|
283 |
sub.update_selected_submissions(user_token=user_sub.user_token, selected_submission_ids=submission_ids)
|
284 |
return {"success": True, "error": ""}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
utils.install_requirements(REQUIREMENTS_FNAME)
|
52 |
|
53 |
|
54 |
+
class UserTeamNameUpdate(BaseModel):
|
55 |
+
user_token: str
|
56 |
+
new_team_name: str
|
57 |
+
|
58 |
+
|
59 |
class User(BaseModel):
|
60 |
user_token: str
|
61 |
|
|
|
198 |
"submissions": "",
|
199 |
"submission_text": SUBMISSION_TEXT.format(COMP_INFO.submission_limit),
|
200 |
"error": "**Invalid token**",
|
201 |
+
"team_name": "",
|
202 |
}
|
203 |
}
|
204 |
subs = subs.to_dict(orient="records")
|
|
|
210 |
submission_text = SUBMISSION_TEXT.format(COMP_INFO.submission_limit)
|
211 |
submission_selection_text = SUBMISSION_SELECTION_TEXT.format(COMP_INFO.selection_limit)
|
212 |
|
213 |
+
team_name = utils.get_team_name(user.user_token, COMPETITION_ID, HF_TOKEN)
|
214 |
+
|
215 |
resp = {
|
216 |
"response": {
|
217 |
"submissions": subs,
|
218 |
"submission_text": submission_text + submission_selection_text,
|
219 |
"error": error,
|
220 |
+
"team_name": team_name,
|
221 |
}
|
222 |
}
|
223 |
return resp
|
|
|
291 |
}
|
292 |
sub.update_selected_submissions(user_token=user_sub.user_token, selected_submission_ids=submission_ids)
|
293 |
return {"success": True, "error": ""}
|
294 |
+
|
295 |
+
|
296 |
+
@app.post("/update_team_name", response_class=JSONResponse)
|
297 |
+
def update_team_name(request: Request, user_team: UserTeamNameUpdate):
|
298 |
+
if USE_OAUTH == 1:
|
299 |
+
if request.session.get("oauth_info") is not None:
|
300 |
+
user_token = request.session.get("oauth_info")["access_token"]
|
301 |
+
|
302 |
+
user_token = user_team.user_token
|
303 |
+
|
304 |
+
try:
|
305 |
+
utils.update_team_name(user_token, user_team.new_team_name, COMPETITION_ID, HF_TOKEN)
|
306 |
+
return {"success": True, "error": ""}
|
307 |
+
except Exception as e:
|
308 |
+
return {"success": False, "error": str(e)}
|
competitions/templates/index.html
CHANGED
@@ -137,7 +137,12 @@
|
|
137 |
// contentDiv.innerHTML = marked.parse(data.response.submission_text) + data.response.submissions;
|
138 |
if (data.response.submissions && data.response.submissions.length > 0 && data.response.error.length == 0) {
|
139 |
// Start building the table HTML
|
140 |
-
let tableHTML =
|
|
|
|
|
|
|
|
|
|
|
141 |
|
142 |
// Iterate over each submission and add it to the table
|
143 |
data.response.submissions.forEach(submission => {
|
@@ -154,10 +159,14 @@
|
|
154 |
// Close the table HTML and set it as the content
|
155 |
tableHTML += '</table>';
|
156 |
tableHTML += '<button id="updateSelectedSubmissionsButton" type="button" class="confirm text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2">Update Selected Submissions</button>';
|
|
|
157 |
contentDiv.innerHTML = marked.parse(data.response.submission_text) + tableHTML;
|
158 |
document.getElementById('updateSelectedSubmissionsButton').addEventListener('click', function () {
|
159 |
updateSelectedSubmissions(userToken);
|
160 |
});
|
|
|
|
|
|
|
161 |
} else {
|
162 |
// Display message if there are no submissions
|
163 |
contentDiv.innerHTML = marked.parse(data.response.submission_text) + marked.parse(data.response.error);
|
@@ -192,6 +201,45 @@
|
|
192 |
});
|
193 |
}
|
194 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
// Find the 'Home' link in the sidebar
|
196 |
const homeLink = document.getElementById('home');
|
197 |
const datasetLink = document.getElementById('dataset');
|
@@ -200,6 +248,7 @@
|
|
200 |
const newSubmission = document.getElementById('new_submission');
|
201 |
const mySubmissions = document.getElementById('my_submissions');
|
202 |
const submissionInfo = document.getElementById('submission_info');
|
|
|
203 |
|
204 |
// Add a click event listener to the 'Home' link
|
205 |
homeLink.addEventListener('click', function (event) {
|
@@ -234,6 +283,10 @@
|
|
234 |
event.preventDefault(); // Prevent the default link behavior
|
235 |
fetchAndDisplaySubmissionInfo(); // Fetch and display info on click
|
236 |
});
|
|
|
|
|
|
|
|
|
237 |
|
238 |
// Fetch and display info when the page loads
|
239 |
fetchAndDisplayCompetitionInfo();
|
@@ -307,6 +360,17 @@
|
|
307 |
<span class="flex-1 ms-3 whitespace-nowrap">Dataset</span>
|
308 |
</a>
|
309 |
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
310 |
<li>
|
311 |
<button type="button"
|
312 |
class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100"
|
@@ -373,18 +437,6 @@
|
|
373 |
</li>
|
374 |
</ul>
|
375 |
</li>
|
376 |
-
<!-- <li>
|
377 |
-
<a href="#"
|
378 |
-
class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100">
|
379 |
-
<svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900"
|
380 |
-
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
381 |
-
viewBox="0 0 20 18">
|
382 |
-
<path
|
383 |
-
d="M14 2a3.963 3.963 0 0 0-1.4.267 6.439 6.439 0 0 1-1.331 6.638A4 4 0 1 0 14 2Zm1 9h-1.264A6.957 6.957 0 0 1 15 15v2a2.97 2.97 0 0 1-.184 1H19a1 1 0 0 0 1-1v-1a5.006 5.006 0 0 0-5-5ZM6.5 9a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9ZM8 10H5a5.006 5.006 0 0 0-5 5v2a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-2a5.006 5.006 0 0 0-5-5Z" />
|
384 |
-
</svg>
|
385 |
-
<span class="flex-1 ms-3 whitespace-nowrap">Team</span>
|
386 |
-
</a>
|
387 |
-
</li> -->
|
388 |
<li id="userToken">
|
389 |
<label for="user_token" class="text-xs font-medium">Hugging Face <a
|
390 |
href="https://huggingface.co/settings/tokens" target="_blank">Token</a> (read-only)
|
@@ -581,4 +633,49 @@
|
|
581 |
}
|
582 |
</script>
|
583 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
584 |
</html>
|
|
|
137 |
// contentDiv.innerHTML = marked.parse(data.response.submission_text) + data.response.submissions;
|
138 |
if (data.response.submissions && data.response.submissions.length > 0 && data.response.error.length == 0) {
|
139 |
// Start building the table HTML
|
140 |
+
let tableHTML = `
|
141 |
+
<div class="flex items-center">
|
142 |
+
<input type="text" name="team_name" id="team_name" class="mt-1 mb-1 block me-2" value="${data.response.team_name}">
|
143 |
+
<button id="updateTeamNameButton" type="button" class="confirm text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2">Update Team Name</button>
|
144 |
+
</div>`;
|
145 |
+
tableHTML += '<table border="1"><tr><th>Datetime</th><th>Submission ID</th><th>Public Score</th><th>Submission Comment</th><th>Selected</th><th>Status</th></tr>';
|
146 |
|
147 |
// Iterate over each submission and add it to the table
|
148 |
data.response.submissions.forEach(submission => {
|
|
|
159 |
// Close the table HTML and set it as the content
|
160 |
tableHTML += '</table>';
|
161 |
tableHTML += '<button id="updateSelectedSubmissionsButton" type="button" class="confirm text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2">Update Selected Submissions</button>';
|
162 |
+
// add a text field which displays team name and a button to update team name
|
163 |
contentDiv.innerHTML = marked.parse(data.response.submission_text) + tableHTML;
|
164 |
document.getElementById('updateSelectedSubmissionsButton').addEventListener('click', function () {
|
165 |
updateSelectedSubmissions(userToken);
|
166 |
});
|
167 |
+
document.getElementById('updateTeamNameButton').addEventListener('click', function () {
|
168 |
+
updateTeamName(userToken);
|
169 |
+
});
|
170 |
} else {
|
171 |
// Display message if there are no submissions
|
172 |
contentDiv.innerHTML = marked.parse(data.response.submission_text) + marked.parse(data.response.error);
|
|
|
201 |
});
|
202 |
}
|
203 |
|
204 |
+
function fetchAndDisplayTeamInfo() {
|
205 |
+
const apiEndpoint = '/team_info';
|
206 |
+
const userToken = document.getElementById('user_token').value;
|
207 |
+
const articleLoadingSpinner = document.getElementById('articleLoadingSpinner');
|
208 |
+
articleLoadingSpinner.classList.remove('hidden');
|
209 |
+
|
210 |
+
const requestOptions = {
|
211 |
+
method: 'POST',
|
212 |
+
headers: {
|
213 |
+
'Content-Type': 'application/json',
|
214 |
+
},
|
215 |
+
body: JSON.stringify({ "user_token": userToken })
|
216 |
+
};
|
217 |
+
fetch(apiEndpoint, requestOptions)
|
218 |
+
.then(response => {
|
219 |
+
if (!response.ok) {
|
220 |
+
throw new Error('Network response was not ok');
|
221 |
+
}
|
222 |
+
return response.json(); // Parse the JSON response
|
223 |
+
})
|
224 |
+
.then(data => {
|
225 |
+
// Populate the 'content' div with the HTML from the response
|
226 |
+
const contentDiv = document.getElementById('content');
|
227 |
+
if (data.team_exists) {
|
228 |
+
contentHTML = "<h2>Team</h2>";
|
229 |
+
contentHTML += "<p>" + data.team_name + "</p>";
|
230 |
+
contentDiv.innerHTML = marked.parse(contentHTML);
|
231 |
+
} else {
|
232 |
+
contentDiv.innerHTML = marked.parse(data.response);
|
233 |
+
}
|
234 |
+
contentDiv.innerHTML = marked.parse(data.response);
|
235 |
+
articleLoadingSpinner.classList.add('hidden');
|
236 |
+
})
|
237 |
+
.catch(error => {
|
238 |
+
console.error('There has been a problem with your fetch operation:', error);
|
239 |
+
articleLoadingSpinner.classList.add('hidden');
|
240 |
+
});
|
241 |
+
}
|
242 |
+
|
243 |
// Find the 'Home' link in the sidebar
|
244 |
const homeLink = document.getElementById('home');
|
245 |
const datasetLink = document.getElementById('dataset');
|
|
|
248 |
const newSubmission = document.getElementById('new_submission');
|
249 |
const mySubmissions = document.getElementById('my_submissions');
|
250 |
const submissionInfo = document.getElementById('submission_info');
|
251 |
+
const teamLink = document.getElementById('team');
|
252 |
|
253 |
// Add a click event listener to the 'Home' link
|
254 |
homeLink.addEventListener('click', function (event) {
|
|
|
283 |
event.preventDefault(); // Prevent the default link behavior
|
284 |
fetchAndDisplaySubmissionInfo(); // Fetch and display info on click
|
285 |
});
|
286 |
+
teamLink.addEventListener('click', function (event) {
|
287 |
+
event.preventDefault(); // Prevent the default link behavior
|
288 |
+
fetchAndDisplayTeamInfo(); // Fetch and display info on click
|
289 |
+
});
|
290 |
|
291 |
// Fetch and display info when the page loads
|
292 |
fetchAndDisplayCompetitionInfo();
|
|
|
360 |
<span class="flex-1 ms-3 whitespace-nowrap">Dataset</span>
|
361 |
</a>
|
362 |
</li>
|
363 |
+
<li>
|
364 |
+
<a href="#" id="team" class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100">
|
365 |
+
<svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900"
|
366 |
+
aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
|
367 |
+
viewBox="0 0 20 18">
|
368 |
+
<path
|
369 |
+
d="M14 2a3.963 3.963 0 0 0-1.4.267 6.439 6.439 0 0 1-1.331 6.638A4 4 0 1 0 14 2Zm1 9h-1.264A6.957 6.957 0 0 1 15 15v2a2.97 2.97 0 0 1-.184 1H19a1 1 0 0 0 1-1v-1a5.006 5.006 0 0 0-5-5ZM6.5 9a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9ZM8 10H5a5.006 5.006 0 0 0-5 5v2a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-2a5.006 5.006 0 0 0-5-5Z" />
|
370 |
+
</svg>
|
371 |
+
<span class="flex-1 ms-3 whitespace-nowrap">Team</span>
|
372 |
+
</a>
|
373 |
+
</li>
|
374 |
<li>
|
375 |
<button type="button"
|
376 |
class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100"
|
|
|
437 |
</li>
|
438 |
</ul>
|
439 |
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
440 |
<li id="userToken">
|
441 |
<label for="user_token" class="text-xs font-medium">Hugging Face <a
|
442 |
href="https://huggingface.co/settings/tokens" target="_blank">Token</a> (read-only)
|
|
|
633 |
}
|
634 |
</script>
|
635 |
|
636 |
+
<script>
|
637 |
+
function updateTeamName(userToken) {
|
638 |
+
const teamName = document.getElementById('team_name').value;
|
639 |
+
const articleLoadingSpinner = document.getElementById('articleLoadingSpinner');
|
640 |
+
articleLoadingSpinner.classList.remove('hidden');
|
641 |
+
|
642 |
+
const updateEndpoint = '/update_team_name';
|
643 |
+
const requestOptions = {
|
644 |
+
method: 'POST',
|
645 |
+
headers: {
|
646 |
+
'Content-Type': 'application/json',
|
647 |
+
},
|
648 |
+
body: JSON.stringify({
|
649 |
+
"user_token": userToken,
|
650 |
+
"new_team_name": teamName
|
651 |
+
})
|
652 |
+
};
|
653 |
+
|
654 |
+
fetch(updateEndpoint, requestOptions)
|
655 |
+
.then(response => {
|
656 |
+
if (!response.ok) {
|
657 |
+
throw new Error('Network response was not ok');
|
658 |
+
}
|
659 |
+
return response.json();
|
660 |
+
})
|
661 |
+
.then(data => {
|
662 |
+
if (data.success) {
|
663 |
+
// Optionally, display a success message or handle accordingly
|
664 |
+
console.log('Update successful');
|
665 |
+
articleLoadingSpinner.classList.add('hidden');
|
666 |
+
} else {
|
667 |
+
// Handle failure case
|
668 |
+
console.log('Update failed');
|
669 |
+
articleLoadingSpinner.classList.add('hidden');
|
670 |
+
alert(data.error);
|
671 |
+
}
|
672 |
+
// Refresh submissions display
|
673 |
+
fetchAndDisplaySubmissions();
|
674 |
+
})
|
675 |
+
.catch(error => {
|
676 |
+
console.error('There was a problem with the fetch operation for updating:', error);
|
677 |
+
});
|
678 |
+
}
|
679 |
+
</script>
|
680 |
+
|
681 |
</html>
|
competitions/utils.py
CHANGED
@@ -230,3 +230,73 @@ def can_user_submit_before_start(user_token, competition_organization):
|
|
230 |
if org["name"] == competition_organization:
|
231 |
return True
|
232 |
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
230 |
if org["name"] == competition_organization:
|
231 |
return True
|
232 |
return False
|
233 |
+
|
234 |
+
|
235 |
+
def get_team_name(user_token, competition_id, hf_token):
|
236 |
+
user_info = user_authentication(token=user_token)
|
237 |
+
user_id = user_info["id"]
|
238 |
+
user_team = hf_hub_download(
|
239 |
+
repo_id=competition_id,
|
240 |
+
filename="user_team.json",
|
241 |
+
token=hf_token,
|
242 |
+
repo_type="dataset",
|
243 |
+
)
|
244 |
+
with open(user_team, "r", encoding="utf-8") as f:
|
245 |
+
user_team = json.load(f)
|
246 |
+
|
247 |
+
if user_id not in user_team:
|
248 |
+
return None
|
249 |
+
|
250 |
+
team_id = user_team[user_id]
|
251 |
+
|
252 |
+
team_metadata = hf_hub_download(
|
253 |
+
repo_id=competition_id,
|
254 |
+
filename="teams.json",
|
255 |
+
token=hf_token,
|
256 |
+
repo_type="dataset",
|
257 |
+
)
|
258 |
+
with open(team_metadata, "r", encoding="utf-8") as f:
|
259 |
+
team_metadata = json.load(f)
|
260 |
+
|
261 |
+
team_name = team_metadata[team_id]["name"]
|
262 |
+
return team_name
|
263 |
+
|
264 |
+
|
265 |
+
def update_team_name(user_token, new_team_name, competition_id, hf_token):
|
266 |
+
user_info = user_authentication(token=user_token)
|
267 |
+
user_id = user_info["id"]
|
268 |
+
user_team = hf_hub_download(
|
269 |
+
repo_id=competition_id,
|
270 |
+
filename="user_team.json",
|
271 |
+
token=hf_token,
|
272 |
+
repo_type="dataset",
|
273 |
+
)
|
274 |
+
with open(user_team, "r", encoding="utf-8") as f:
|
275 |
+
user_team = json.load(f)
|
276 |
+
|
277 |
+
if user_id not in user_team:
|
278 |
+
raise Exception("User is not part of a team")
|
279 |
+
|
280 |
+
team_id = user_team[user_id]
|
281 |
+
|
282 |
+
team_metadata = hf_hub_download(
|
283 |
+
repo_id=competition_id,
|
284 |
+
filename="teams.json",
|
285 |
+
token=hf_token,
|
286 |
+
repo_type="dataset",
|
287 |
+
)
|
288 |
+
with open(team_metadata, "r", encoding="utf-8") as f:
|
289 |
+
team_metadata = json.load(f)
|
290 |
+
|
291 |
+
team_metadata[team_id]["name"] = new_team_name
|
292 |
+
team_metadata_json = json.dumps(team_metadata, indent=4)
|
293 |
+
team_metadata_json_bytes = team_metadata_json.encode("utf-8")
|
294 |
+
team_metadata_json_buffer = io.BytesIO(team_metadata_json_bytes)
|
295 |
+
api = HfApi(token=hf_token)
|
296 |
+
api.upload_file(
|
297 |
+
path_or_fileobj=team_metadata_json_buffer,
|
298 |
+
path_in_repo="teams.json",
|
299 |
+
repo_id=competition_id,
|
300 |
+
repo_type="dataset",
|
301 |
+
)
|
302 |
+
return new_team_name
|