Skip to content

Commit 365396a

Browse files
committed
feat: add duplicate detection, capacity enforcement, and waitlist to registration
- Detect duplicate registrations and close with friendly message - Add capacity check (75 max) with waitlist label for overflow - Deduplicate CSV export by GitHub username - Update welcome message with custom text - Add duplicate warning to issue template - Registration page dynamically switches to waitlist mode when full - Polish language across all scenario paths - Remove recursive trigger (labeled event) that caused workflow failures
1 parent 559ca5f commit 365396a

File tree

3 files changed

+197
-20
lines changed

3 files changed

+197
-20
lines changed

.github/ISSUE_TEMPLATE/workshop-registration.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ body:
1414
**Cost:** Free
1515
**Capacity:** 75 participants
1616
17+
**Important:** Please submit this form only once. If you have already registered, you do not need to register again - your spot is saved. Duplicate registrations will be automatically closed.
18+
1719
Filling out this form is your first GitHub interaction - and it counts. You are already learning. All fields below are accessible with NVDA, JAWS, and VoiceOver.
1820
1921
- type: input

.github/workflows/registration.yml

Lines changed: 144 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Registration - Welcome & CSV Export
22

33
on:
44
issues:
5-
types: [opened, edited, labeled]
5+
types: [opened]
66
workflow_dispatch:
77

88
permissions:
@@ -18,31 +18,150 @@ jobs:
1818
github.event.action == 'opened' &&
1919
contains(github.event.issue.title, '[REGISTER]')
2020
steps:
21+
- name: Check for duplicate registration
22+
id: dup-check
23+
uses: actions/github-script@v7
24+
with:
25+
script: |
26+
const username = context.payload.issue.user.login;
27+
const currentIssueNumber = context.issue.number;
28+
29+
// Find existing registration issues by this user
30+
const existingIssues = await github.paginate(github.rest.issues.listForRepo, {
31+
owner: context.repo.owner,
32+
repo: context.repo.repo,
33+
labels: 'registration',
34+
state: 'all',
35+
per_page: 100
36+
});
37+
38+
const priorRegistration = existingIssues.find(
39+
issue => issue.user.login === username && issue.number !== currentIssueNumber
40+
);
41+
42+
if (priorRegistration) {
43+
core.setOutput('is_duplicate', 'true');
44+
core.setOutput('original_issue', priorRegistration.number);
45+
} else {
46+
core.setOutput('is_duplicate', 'false');
47+
}
48+
49+
- name: Handle duplicate registration
50+
if: steps.dup-check.outputs.is_duplicate == 'true'
51+
uses: actions/github-script@v7
52+
with:
53+
script: |
54+
const originalIssue = ${{ steps.dup-check.outputs.original_issue }};
55+
56+
await github.rest.issues.createComment({
57+
owner: context.repo.owner,
58+
repo: context.repo.repo,
59+
issue_number: context.issue.number,
60+
body: `## You are already registered!
61+
62+
Hi @${context.payload.issue.user.login}, it looks like you already registered in issue #${originalIssue}. No need to register again — your spot is saved!
63+
64+
We have closed this issue since your original registration is already on file. If you need to update your details, please comment on your original issue #${originalIssue}.
65+
66+
Questions? Email [support@bits-acb.org](mailto:support@bits-acb.org).`
67+
});
68+
69+
await github.rest.issues.addLabels({
70+
owner: context.repo.owner,
71+
repo: context.repo.repo,
72+
issue_number: context.issue.number,
73+
labels: ['duplicate']
74+
});
75+
76+
await github.rest.issues.update({
77+
owner: context.repo.owner,
78+
repo: context.repo.repo,
79+
issue_number: context.issue.number,
80+
state: 'closed',
81+
state_reason: 'not_planned'
82+
});
83+
84+
- name: Check capacity
85+
id: capacity-check
86+
if: steps.dup-check.outputs.is_duplicate == 'false'
87+
uses: actions/github-script@v7
88+
with:
89+
script: |
90+
const MAX_CAPACITY = 75;
91+
92+
// Count unique registered users (excluding this issue)
93+
const existingIssues = await github.paginate(github.rest.issues.listForRepo, {
94+
owner: context.repo.owner,
95+
repo: context.repo.repo,
96+
labels: 'registration',
97+
state: 'all',
98+
per_page: 100
99+
});
100+
101+
const currentIssueNumber = context.issue.number;
102+
const uniqueUsers = new Set();
103+
for (const issue of existingIssues) {
104+
if (issue.number !== currentIssueNumber) {
105+
uniqueUsers.add(issue.user.login);
106+
}
107+
}
108+
109+
const currentCount = uniqueUsers.size;
110+
core.setOutput('count', currentCount);
111+
112+
if (currentCount >= MAX_CAPACITY) {
113+
core.setOutput('is_full', 'true');
114+
} else {
115+
core.setOutput('is_full', 'false');
116+
}
117+
118+
- name: Handle registration full
119+
if: steps.dup-check.outputs.is_duplicate == 'false' && steps.capacity-check.outputs.is_full == 'true'
120+
uses: actions/github-script@v7
121+
with:
122+
script: |
123+
await github.rest.issues.createComment({
124+
owner: context.repo.owner,
125+
repo: context.repo.repo,
126+
issue_number: context.issue.number,
127+
body: `## Registration is currently full
128+
129+
Hi @${context.payload.issue.user.login}, thank you for your interest in GIT Going with GitHub! Unfortunately, all 75 spots have been filled.
130+
131+
We have added you to the waitlist. If a spot opens up, we will let you know right here on this issue.
132+
133+
Questions? Email [support@bits-acb.org](mailto:support@bits-acb.org).`
134+
});
135+
136+
await github.rest.issues.addLabels({
137+
owner: context.repo.owner,
138+
repo: context.repo.repo,
139+
issue_number: context.issue.number,
140+
labels: ['waitlist']
141+
});
142+
21143
- name: Post welcome comment
144+
if: steps.dup-check.outputs.is_duplicate == 'false' && steps.capacity-check.outputs.is_full == 'false'
22145
uses: actions/github-script@v7
23146
with:
24147
script: |
25148
await github.rest.issues.createComment({
26149
owner: context.repo.owner,
27150
repo: context.repo.repo,
28151
issue_number: context.issue.number,
29-
body: `## You are registered for GIT Going with GitHub!
152+
body: `## Welcome to GIT Going with GitHub!
30153
31-
Welcome, @${context.payload.issue.user.login}! Your registration has been received.
154+
Hi @${context.payload.issue.user.login}, thank you for registering! We are excited to have you join us.
32155
33-
**Workshop details:**
34-
- **Dates:** Saturday, March 7 & Sunday, March 8, 2026
35-
- **Time:** 12:00 PM - 8:00 PM Eastern (both days)
36-
- **Location:** Online via Zoom (link will be emailed before the event)
156+
Your registration has been confirmed. Additional information, including the Zoom link and pre-workshop preparation materials, will be sent to you soon.
37157
38-
**What to do next:**
39-
1. Complete the [Pre-Workshop Setup Guide](https://bits-acb.github.io/git-going-with-github/docs/00-pre-workshop-setup.html) before March 7
40-
2. Questions? Email [support@bits-acb.org](mailto:support@bits-acb.org)
158+
In the meantime, if you have any questions, feel free to email us at [support@bits-acb.org](mailto:support@bits-acb.org).
41159
42-
You just filed a GitHub issue - your first open source contribution. Welcome to the community.`
160+
See you on March 7! Welcome aboard.`
43161
});
44162
45163
- name: Add registration label
164+
if: steps.dup-check.outputs.is_duplicate == 'false' && steps.capacity-check.outputs.is_full == 'false'
46165
uses: actions/github-script@v7
47166
with:
48167
script: |
@@ -62,7 +181,9 @@ jobs:
62181
runs-on: ubuntu-latest
63182
if: >-
64183
(github.event_name == 'workflow_dispatch') ||
65-
(github.event_name == 'issues' && contains(github.event.issue.title, '[REGISTER]'))
184+
(github.event_name == 'issues' &&
185+
github.event.action == 'opened' &&
186+
contains(github.event.issue.title, '[REGISTER]'))
66187
steps:
67188
- name: Checkout repository
68189
uses: actions/checkout@v4
@@ -118,10 +239,18 @@ jobs:
118239
119240
let csv = headers.join(',') + '\n';
120241
121-
for (const issue of issues) {
242+
// Deduplicate by GitHub username, keeping only the earliest registration
243+
const seen = new Set();
244+
const sortedIssues = issues.sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
245+
246+
for (const issue of sortedIssues) {
247+
const username = issue.user.login;
248+
if (seen.has(username)) continue;
249+
seen.add(username);
250+
122251
const row = [
123252
issue.created_at.split('T')[0],
124-
issue.user.login,
253+
username,
125254
parseField(issue.body, 'First Name'),
126255
parseField(issue.body, 'Last Name'),
127256
parseField(issue.body, 'Email Address'),
@@ -137,7 +266,7 @@ jobs:
137266
// Write CSV file
138267
fs.mkdirSync('.github/data', { recursive: true });
139268
fs.writeFileSync('.github/data/registrations.csv', csv, 'utf-8');
140-
console.log(`Exported ${issues.length} registration(s) to .github/data/registrations.csv`);
269+
console.log(`Exported ${seen.size} unique registration(s) from ${issues.length} total issue(s) to .github/data/registrations.csv`);
141270
142271
- name: Commit and push CSV
143272
run: |

html/REGISTER.html

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@
3131
<main id="main-content" class="markdown-body">
3232
<h1>Register for GIT Going with GitHub</h1>
3333
<p><a href="https://bits-acb.github.io/git-going-with-github/">Back to Home</a> | <a href="https://github.com/BITS-ACB/git-going-with-github/discussions">Discussion Forum</a> | <a href="https://bits-acb.github.io/git-going-with-github/COMING_SOON.html">Pre-Workshop Setup Guide</a></p>
34-
<p>Registration requires two steps. Both are required to complete your registration.</p>
34+
<div id="registration-open-intro">
35+
<p>Registration requires two steps. Both steps are required.</p>
36+
</div>
37+
<div id="registration-full-banner" style="display: none;">
38+
<blockquote>
39+
<p><strong>Registration is currently full.</strong> All 75 spots have been filled. You can still join the waitlist by filing a GitHub issue below. If a spot opens up, we will contact you.</p>
40+
</blockquote>
41+
</div>
3542
<table>
3643
<thead>
3744
<tr>
@@ -65,6 +72,7 @@ <h1>Register for GIT Going with GitHub</h1>
6572
<blockquote>
6673
<p><strong>Already registered?</strong> Complete the <a href="https://bits-acb.github.io/git-going-with-github/COMING_SOON.html"><strong>Pre-Workshop Setup Guide</strong></a> before March 7. It walks you through GitHub account setup, screen reader configuration, <a href="https://code.visualstudio.com/">VS Code</a>, and <a href="https://github.com/features/copilot">GitHub Copilot</a> - with instructions for NVDA, JAWS, and VoiceOver.</p>
6774
</blockquote>
75+
<div id="section-zoom">
6876
<hr>
6977
<h2>Step 1 - Register for the Zoom Session</h2>
7078
<p>Register for the Zoom session so you receive the meeting link before the workshop.</p>
@@ -76,9 +84,13 @@ <h2>Step 1 - Register for the Zoom Session</h2>
7684
<ul>
7785
<li>The <a href="https://zoom.us/">Zoom</a> client works well with <a href="https://www.nvaccess.org/download/">NVDA</a>, <a href="https://www.freedomscientific.com/products/software/jaws/">JAWS</a>, and <a href="https://support.apple.com/guide/voiceover/welcome/mac">VoiceOver</a></li>
7886
</ul>
87+
</div>
7988
<hr>
80-
<h2>Step 2 - Sign Up on GitHub</h2>
81-
<p>File a GitHub issue to register. This is intentional - filing an issue is one of the first skills you will learn in this workshop, so you are already practicing.</p>
89+
<h2 id="github-step-heading">Step 2 - Sign Up on GitHub</h2>
90+
<div id="section-waitlist-heading" style="display: none;">
91+
<h2>Join the Waitlist</h2>
92+
</div>
93+
<p id="github-step-description">File a GitHub issue to register. This is intentional - filing an issue is one of the first skills you will learn in this workshop, so you are already practicing.</p>
8294
<p>You must be signed into a <a href="https://github.com">GitHub</a> account to file the issue. If you do not have one yet, create one first using the steps below - then come back to file your registration issue.</p>
8395
<h3>Need a GitHub Account?</h3>
8496
<p>If you do not have a GitHub account yet, follow these steps:</p>
@@ -95,10 +107,10 @@ <h3>Need a GitHub Account?</h3>
95107
</ol>
96108
<p>After creating your account, check your email for a message from GitHub with the subject &quot;Please verify your email address&quot; and activate the link inside it.</p>
97109
<p><strong>Enable two-factor authentication</strong> (strongly recommended): Go to <a href="https://github.com/settings/security">github.com/settings/security</a>, find &quot;Two-factor authentication,&quot; and activate &quot;Enable.&quot; An authenticator app (Microsoft Authenticator, Google Authenticator, or Authy) is the most reliable option.</p>
98-
<h3>File Your Registration Issue</h3>
110+
<h3 id="file-issue-heading">File Your Registration Issue</h3>
99111
<p><strong>Important:</strong> You must be signed into your GitHub account before clicking the link below. If you are not signed in, go to <a href="https://github.com">github.com</a> and sign in first.</p>
100112
<blockquote>
101-
<p><a href="https://github.com/BITS-ACB/git-going-with-github/issues/new?template=workshop-registration.yml&title=%5BREGISTER%5D+GIT+Going+with+GitHub+-+March+2026"><strong>Start Step 2 - File your registration issue</strong></a></p>
113+
<p><a id="file-issue-link" href="https://github.com/BITS-ACB/git-going-with-github/issues/new?template=workshop-registration.yml&title=%5BREGISTER%5D+GIT+Going+with+GitHub+-+March+2026"><strong>Start Step 2 - File your registration issue</strong></a></p>
102114
</blockquote>
103115
<p><strong>Note:</strong> The issue title is pre-filled and required by GitHub. You do not need to change it - just fill out the form fields below it and submit.</p>
104116
<p>The form asks for:</p>
@@ -112,6 +124,7 @@ <h3>File Your Registration Issue</h3>
112124
</ul>
113125
<p>After you submit, you will receive an automated confirmation comment on your issue. Your GitHub username is captured automatically - you do not need to enter it.</p>
114126
<hr>
127+
<div id="section-what-happens-open">
115128
<h2>What Happens Next</h2>
116129
<p>Once you have completed both steps:</p>
117130
<ol>
@@ -120,6 +133,16 @@ <h2>What Happens Next</h2>
120133
<li>Complete the <a href="https://bits-acb.github.io/git-going-with-github/COMING_SOON.html">Pre-Workshop Setup Guide</a> before March 7 - it covers GitHub account setup, screen reader configuration, <a href="https://code.visualstudio.com/">VS Code</a>, and <a href="https://github.com/features/copilot">GitHub Copilot</a></li>
121134
<li>Questions? Email <a href="mailto:support@bits-acb.org">support@bits-acb.org</a></li>
122135
</ol>
136+
</div>
137+
<div id="section-what-happens-waitlist" style="display: none;">
138+
<h2>What Happens Next</h2>
139+
<p>After filing your waitlist issue:</p>
140+
<ol>
141+
<li>You will see a confirmation comment on your GitHub issue letting you know you are on the waitlist</li>
142+
<li>If a spot opens up, we will let you know through your GitHub issue</li>
143+
<li>Questions? Email <a href="mailto:support@bits-acb.org">support@bits-acb.org</a></li>
144+
</ol>
145+
</div>
123146
<hr>
124147
<h2>While You Wait</h2>
125148
<ul>
@@ -136,6 +159,7 @@ <h2>While You Wait</h2>
136159
</footer>
137160
<script>
138161
(function() {
162+
var MAX_CAPACITY = 75;
139163
var url = 'https://api.github.com/search/issues?q=repo:BITS-ACB/git-going-with-github+label:registration+is:issue+is:open';
140164
var xhr = new XMLHttpRequest();
141165
xhr.open('GET', url);
@@ -148,6 +172,28 @@ <h2>While You Wait</h2>
148172
for (var i = 0; i < els.length; i++) {
149173
els[i].textContent = count;
150174
}
175+
176+
if (count >= MAX_CAPACITY) {
177+
// Hide registration-open content
178+
var hideIds = ['registration-open-intro', 'section-zoom', 'github-step-heading', 'section-what-happens-open'];
179+
for (var h = 0; h < hideIds.length; h++) {
180+
var el = document.getElementById(hideIds[h]);
181+
if (el) el.style.display = 'none';
182+
}
183+
// Show waitlist content
184+
var showIds = ['registration-full-banner', 'section-waitlist-heading', 'section-what-happens-waitlist'];
185+
for (var s = 0; s < showIds.length; s++) {
186+
var el = document.getElementById(showIds[s]);
187+
if (el) el.style.display = '';
188+
}
189+
// Update text for waitlist context
190+
var desc = document.getElementById('github-step-description');
191+
if (desc) desc.textContent = 'File a GitHub issue to join the waitlist. Filing an issue is one of the first skills you will learn in this workshop, so you are already practicing.';
192+
var heading = document.getElementById('file-issue-heading');
193+
if (heading) heading.textContent = 'File Your Waitlist Issue';
194+
var link = document.getElementById('file-issue-link');
195+
if (link) link.innerHTML = '<strong>File your waitlist issue</strong>';
196+
}
151197
} catch (e) {}
152198
}
153199
};

0 commit comments

Comments
 (0)