Skip to content

Content fixes after the archive: privacy policy, glossary, event listings, and meta description - #222

Merged
DZPM merged 7 commits into
editionfrom
work/after-archive
Oct 27, 2026
Merged

DZPM merged 7 commits into
editionfrom
work/after-archive

Conversation

@DZPM

@DZPM DZPM commented Oct 25, 2026

Copy link
Copy Markdown
Member

Content fixes after the archive went live: the privacy policy, the words the site uses, the event listings, and the meta description. Six commits, each one with its reasons and measured figures in its message.

🚧 For the board: the privacy policy changes

The policy said that every person page was sent by the person, under their consent. That is no longer true, so the policy now says:

  • Person pages built from our Meetup announcements (204 of the 370): the name, the talks, and the events. The basis is the legitimate interest of the association in keeping the history of the community (GDPR article 6.1.f). A person can object, and we remove the page.
  • Event photographs (530, from the posts of the association on X): a new section. They show the event in general, and the basis is the same legitimate interest. A person can object to a photograph in which they appear, and we remove it.
  • Unsplash is gone from the list of third parties (the page headers are gone), and Eventbrite is added (one button on PyDay BCN 2018).

I validated it, but the policy belongs to the association: please say so here if something is wrong.

What changes

  • Glossary: Board, Committee (Permanent Committee in full), Event organizers, Attendees, and Meetup RSVPs. The menu "Organizers" is now "Who we are". "Members" means only the members of the association. URLs do not change; /people/role/assistants/ redirects to /people/role/attendees/.
  • Home page counts: Events, Talks, People ("Speakers, organizers, and others"), Board and Committee, Meetup RSVPs, and Sponsors. Every number equals the count on the page it links to. The RSVPs link to the Attendees page, which says that an RSVP is not attendance.
  • Event listings: /events/meetups/ and the other series were in alphabetical order. They now use the table of /events/, by year and month, and the five pages share one bar of tabs, as /people/ does.
  • Meta description: every page has one, and a shared link shows the same sentence.
  • rel="noopener" on every link that opens a new tab.
  • American English in the site's own text, as languageCode, the URLs, and the code already are. Imported text (talk titles and descriptions) does not change.

Checks

Built with -D: 1379 pages. bin/check-content 0 errors (79 old photo warnings), bin/check-html-safety PASS, bin/check-rendered PASS.

Not in this PR

Bootstrap, jQuery, and Hugo upgrades go in a separate PR, to keep content and layout apart.

DZPM added 6 commits October 25, 2026 09:41
A link with target="_blank" and no rel="noopener" hands the opened page a
handle on this one (window.opener), which a hostile page can use to send
the reader somewhere else. Modern browsers imply noopener, older ones do
not, and the security audit counted 7 such links on the home page.

Five templates (the footer, the people summary, the contact page, the
event detail, and the agenda) and two pages with raw HTML (PyDay BCN
2018, 7 links, and the 2022 Django workshop of PyLadies BCN, 1 link) get
rel="noopener", next to any rel value they already had.

Measured on a -D build, the frozen pages under archives/ left out: no
link with target="_blank" lacks noopener.

bin/check-content: 0 errors, 79 warnings. bin/check-html-safety and
bin/check-rendered: PASS.
The policy and humans.txt described the site before phases 3 and 4.
Measured on a -D build, the frozen pages under archives/ left out:

- Unsplash: the policy said the page headers load images from
  unsplash.com. Phase 4 removed the headers, and no page loads anything
  from Unsplash now. The sentence now says that scripts, styles, fonts,
  and images come from this site, except the PayPal button of the
  membership pages and the Eventbrite button of PyDay BCN 2018.
- Eventbrite: it was missing from "Who else sees your data". It is there
  now, next to the other companies.
- No photograph: the policy said a person page shows a silhouette. A
  person page shows the initials of the name on a colour (246 of the 370
  person records have no photograph); only the grids of organizers or
  speakers on four event pages show a silhouette.
- Where a person page comes from: the policy said every person sent
  their photograph and text, under their consent. The 204 person records
  that the archive built from our Meetup announcements were not sent by
  anybody. For those pages the basis is now the legitimate interest of
  the association in keeping the history of the community (GDPR article
  6.1.f), and the reader can object and have the page removed.
- Event photographs: the 530 photographs of the galleries come from the
  posts of the association on X and were not in the policy. A new
  section says where they come from, that they show the event in
  general, the basis (GDPR article 6.1.f), and that a person can object
  to a photograph and we remove it.
- humans.txt said that no page asks another site for anything to draw
  itself. False: 218 pages carry the youtube-nocookie player, the two
  talk proposal pages embed a Google Form, PyDay BCN 2019 embeds a
  Google Calendar, and PayPal and Eventbrite serve one button each. The
  line now names them and points at the policy for the whole list.

bin/check-content: 0 errors, 79 warnings. bin/check-html-safety and
bin/check-rendered: PASS.
No page had a <meta name="description">, so a search engine showed
whatever text it picked from the page: often the bar and the first menu
items. og:description and twitter:description read .Summary, which is
the start of a bio on a person page and a slice of a table on a page
with raw HTML.

The meta description now comes, in order, from the description of the
front matter; for a talk, who gave it, at which event, and on which day;
for an event, its type, its date, and its venue; for a person, the name
and the roles the archive credits, with a serial comma; and else the new
site description in config.toml. It is cut at 160 characters on a word.
The two share tags read the same sentence.

Measured on a -D build: 1309 of 1321 pages carry the meta description,
and the 12 without it are alias redirects. 1309 carry og:description.
Samples: "Talk by David Arcos at Python July Meetup, 28 July 2016.",
"Monthly meetup on 16 September 2026 at Dow Jones.", and "David Arcos:
Permanent Committee, Organizer, Speaker, and Mentor at Python
Barcelona."

bin/check-content: 0 errors, 79 warnings. bin/check-html-safety and
bin/check-rendered: PASS.
…tendees, RSVPs

One vocabulary for the words the site uses about people and numbers,
decided on 2026-10-25:

- Board: the junta is "Board" in visible text. The levels of the Who we
  are page are "Board (2026)" and "Former Board (2018 - 2025)" (they
  were "Management Board"). The addresses of the two role pages do not
  move: the people adapter keeps management-board-2026 and
  former-management-board-2018-2025, because a published release links
  the first one. The Information, Legal notice, and Privacy policy
  pages and the association-identity shortcode say "Board" as well.
- Committee: the Comitè Permanent keeps its full name, "Permanent
  Committee", where it is named as a role (its tab, the roles of a
  person). Nothing changed there.
- Event organizer: the role of the people an event page credits under
  Organizers (23 of them today, the PyLadies BCN organizers included)
  is "Event organizer", and its page is titled "Event organizers". Its
  address stays /people/role/organizer/.
- Who we are: the menu entry and title of /pybcn_association/organizers/
  (it was "Organizers", which now names a role). The address stays, and
  the intro of /people/ links the page by its new name.
- Members: only the paying members of the association. Three sentences
  used the word for a Meetup group (Information, Promote your event) or
  a Google Group (Privacy policy) and say "people" or "belong to" now.
- Attendees: the tab that was "Assistants" (a calque of the Catalan
  assistent). Its page moved to /people/role/attendees/, and the
  adapter declares the old address as an alias: Hugo 0.139.4 accepts
  "aliases" in AddPage and wrote the redirect.
- RSVPs: the yes count of Meetup, which the meetup pages printed as
  "Registrations". The visible word is "RSVPs" on the meetup pages, the
  meetups listing, Monthly Events, and the Attendees page, and in the
  docs and bin/new-meetup. The front matter key stays attendance, and
  the meaning stays: an RSVP is a promise to come, not a seat filled.

The tabs of /people/ read the title of each page, as the tabs of /talks/
do, so a tab says "Speakers" and "Event organizers", not the singular
label of a row.

The home page counts six things instead of four, and the number of a
tile is the number of the page it leads to: Events 281 (the h1 of
/events/), Talks 607 (/talks/), People 371 (the h1 of /people/, every
record of the archive, with the caption "Speakers, organizers, and
others" under the label), Board and Committee 11 (the people under the
two home_faces levels of Who we are, Board (2026) 5 and Permanent
Committee 6, nobody on both; the tile lands on #board-2026, because the
level headings of partials/people-grid.html carry an id from their name
now), Meetup RSVPs 8,917 (the sum of attendance over the 267 meetup
pages that carry it, of 268), and Sponsors 82 (the h1 of /sponsors/).
The RSVPs tile leads to the Attendees page, which prints the same sum
from the same partial (partials/meetup_rsvps.html, through
partials/attendees_note.html) and says in plain words what it is: the
"RSVP: yes" answers on Meetup, not who came, which nobody recorded. All
the figures are computed at build time and printed with a thousands
separator; the grid of the tiles is two rows of three from 992px (it
was one row of four), the rows of one height. Measured with Playwright
at 1440 and 390 px: no overflow, every label on one line, the caption
of People on a second.

Measured on a -D build before and after (static/archives/ excluded):
pages with "registrations" 270 to 0, pages with "Assistants" 19 to 0,
pages with "Management Board" 4 to 0, pages with "RSVPs" 0 to 271.
1379 HTML pages (1378 before: the alias). bin/check-content 0 errors
and 79 pre-existing warnings, bin/check-html-safety and
bin/check-rendered pass.

Left as they are, for a decision: "PyLadies BCN Organizers", the title
and menu entry of /pyladies_bcn/organizers-and-speakers/; the
"Organising Committee" credits of the PyDay and PyData programmes
(credited_as, a fact of the record); "work group members" on the
Information page, which is about the work groups and not about Meetup.
The index pages of the four series under /events/ (meetups, pyday_bcn,
pydatabcn, other_events) took the fallback layouts/_default/list.html,
a list of titles in alphabetical order: /events/meetups/ read "Python
Meetup April" of one year before "Python Meetup August" of another,
268 times. They now draw the table of /events/, grouped by year and by
month, newest first, with the same six columns, the jump bar of their
years (when there are two or more), and the legend of their types, cut
to the events of the series. The h1 carries the number of rows,
"Monthly meetups (268)", as "Events (281)" does.

Where the code went. The body of layouts/_default/events_index.html
(the intro, the rows, the jump bar, the legend, and the call to
partials/event_table.html) is partials/event_listing.html, which that
layout and the new layouts/events/list.html both call, so a series
page cannot list an event differently from /events/. Hugo picks
events/list.html for the nested section pages by their type and looks
up the events_index layout of /events/ before it, so /events/ did not
move. partials/event_row.html returns the type token of a row, which
the legend counts rows by: on /events/ that gives the figures
partials/listing_counts.html gave before, checked below, and on a
series page the figures of that page alone. partials/listing_total.html
counts the rows of a section page of events for its h1.

No PyLadies BCN section lists events: /pyladies_bcn/meetups/ is the
Meetup link page (monthly_events layout), and the PyLadies BCN meetups
are rows of /events/meetups/, 71 of them, marked in its legend.

Measured on a -D build before and after. Rows: /events/ 281 and 281,
with the same legend (155 monthly meetups, 72 PyLadies BCN meetups, 23
coding dojos, 9 practice sessions, 9 PyDay BCN editions, 6 barbecues, 2
PyDataBCN editions, 2 sprints, 1 coderetreat, 1 hackathon, 1 workshop).
/events/meetups/ 268 titles to 268 rows under 20 years;
/events/pyday_bcn/ 9 to 9; /events/pydatabcn/ 1 to 1 (no jump bar);
/events/other_events/ 3 to 3. Pages with a section_index list under
/events/ 4 to 0. 1379 HTML pages before and after. bin/check-content 0
errors and 79 pre-existing warnings, bin/check-html-safety and
bin/check-rendered pass. Playwright at 1440 and 390 px on
/events/meetups/ and /events/pyday_bcn/: no horizontal overflow, the
rows reflow as on /events/.

The tabs.

/events/ and the index of each series under it (/events/meetups/,
/events/pyday_bcn/, /events/pydatabcn/, /events/other_events/) draw
one bar of tabs above their rows, All and the four series with their
counts, the current one marked with aria-current="page":

    [ All 281 ] [ Monthly meetups 268 ] [ PyDay BCN 9 ] [ PyDataBCN 1 ] [ Other events 3 ]

The bar is partials/filter_tabs.html, the one /talks/ and /people/
draw, called from the new partials/events_tabs.html out of
partials/event_listing.html, so the two layouts that share that body
share the tabs. No new page and no script: the views were already the
section pages, so the tabs are read from the sections of /events/
(a section with no event gets no tab), their text is the title of the
section page, and the URLs do not move.

The count of a tab is the count the h1 of its page prints, both from
the one test of a row, a page of the events section with a year, filed
under its CurrentSection. The order is the one of the Events menu, by
the weight of the section page, with the meetups (no weight, 268 of
the 281 rows) in front. No glyph on a tab: a series is not a type, the
meetups hold eleven of them, so the legend under the tabs keeps that
job.

Measured on a -D build and on the dev server. On each of the five
pages the bar lists the five tabs above, exactly one tab carries
aria-current and it is the page itself, and each count equals the
number in the h1 of the page the tab leads to (281, 268, 9, 1, 3; the
four add up to 281). Playwright at 1440 and 390 px on the five pages:
scrollWidth equals clientWidth, the tabs take one line at 1440 and
three at 390. 1379 HTML pages before and after. bin/check-content 0
errors and 79 pre-existing warnings; bin/check-html-safety and
bin/check-rendered pass.
config.toml declares en-us, og:locale is en_US, the URLs and the role
ids say "organizer", and CSS and Hugo write color and center, while the
text of the site mixed both spellings: 142 -ize forms against 18 -ise,
but "programme" 71 times against "program" once, and "colour" 26 against
"color" 20. The visible text of a -D build, archives excluded, carried
377 "programme", 22 "organis-", 10 "colour", 5 "behaviour", 2
"favourite", and 1 "licence"; it now carries 0, 6, 9, 5, 0, and 0.

What changed: templates and partials (text and comments), the section
intros and the association and PyLadies pages, the comments of the
event front matter, data/event_emoji.yaml, the SCSS comments, AGENTS.md,
README.md, CONTRIBUTING.md, LICENSING.md, the comments and messages of
bin/, and one workflow comment. organise, programme, colour, licence,
centre, favourite, behaviour, recognise, normalise, labelled, neighbour,
honours, and learnt take their American forms. The credited_as strings
"<Edition> Organising Committee" and "Organizing Committee" (PyDay BCN
2021 to 2025, PyDataBCN 2023), written by the association when it made
each page, read "<Edition> organizers".

What stays: imported talk titles, descriptions, and captions, event
announcements, the bios people wrote, the prompt in bin/prompts/, every
URL, slug, id, and identifier (site_licence, centre_x, normalise_scheme,
PALETTE_COLOURS, aria-labelledby, the "grey" palette token), and the
LICENSE file. The six remaining "organis-" and nine "colour" of the
build are all in imported text or a bio.

Verified: bin/check-content (0 errors, 79 warnings, the photo warnings
of before), bin/check-html-safety, bin/check-rendered on the -D build
(1379 pages, as before), and bin/check-extraction --selftest (7 of 7).
@DZPM DZPM self-assigned this Oct 25, 2026
@DZPM
DZPM requested a review from a team as a code owner October 25, 2026 19:47
@DZPM
DZPM requested review from ber2, mesejo and mrswats October 25, 2026 19:49
Some event pages show photographs from the posts of the association on X, with the caption they were posted with. Only photographs that the association published itself are on the site. They show the event in general: a speaker gave the talk in public and accepted that it was recorded, and the audience appears in the background and from a distance.

- **Where it comes from**: the public posts of the association on X.
- **Why we have it**: our legitimate interest in keeping the history of the community (GDPR article 6.1.f). You can object to a photograph in which you appear, and we remove it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can someone object?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the last line: https://pybcn.org/people/daniel-mesejo-leon/

To change or remove anything on it, edit that file on GitHub and open a pull request, or write to pybcn@googlegroups.com.

image

It's in the privacy policy too, but in each person's url is more convenient, right?

- **Where it comes from**: the person. Each one sent the photograph and wrote or approved the text for publication here. Someone who did not want a photograph did not send one, and the page shows a silhouette instead.
- **Why we have it**: with the person's consent (GDPR article 6.1.a). You can withdraw it at any time, and we remove the page. Withdrawing consent does not affect what was published before.
- **Where it comes from**: for most people, the person. They sent the photograph and wrote or approved the text for publication here. For speakers that the archive credits, the public announcements of our own Meetup events: the page then shows the name, the talks, and the events. A page with no photograph shows the initials of the name on a colour instead; the grid of organizers or speakers on an event page shows a silhouette.
- **Why we have it**: for a page that the person sent, their consent (GDPR article 6.1.a). You can withdraw it at any time, and we remove the page. Withdrawing consent does not affect what was published before. For a page built from our announcements, our legitimate interest in keeping the history of the community (GDPR article 6.1.f). You can object to it, and we remove the page.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a link to a reputable source confirming that this is the actual (and best) GDPR article we want to reference?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. The official text is the GDPR on EUR-Lex: https://eur-lex.europa.eu/eli/reg/2016/679/oj. Article 6(1)(f) is the legitimate interest basis, and Article 21 gives the right to object to it, which the policy now links from both bullets (83c39af). Consent (6(1)(a)) does not fit here: nobody asked the 204 speakers built from our announcements, or the people in the 530 photographs. I am not a lawyer, so if the board wants a second opinion, this is the paragraph to show.


## Past Management Boards
* Management Board 2018 - 2025
## Past Boards

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this was the only board from 2018 to 2025? @DZPM, weren't you the president at some point? Or does this refer to the board of the nonprofit organization?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I was never president. The association was founded in 2018, and there was only one board before the current one, from 2018 to 2025, with Laura as president. Before 2018 there was no association, so no board: just the meetup group.

partials/filter_tabs.html.

[ All 371 ] [ 📋 Management Board (2026) 4 ] [ 🧭 Permanent Committee 6 ] [ 🧭 Organizer 21 ] ... [ Assistants ]
[ All 371 ] [ 🎤 Speakers 356 ] [ 🧭 Event organizers 23 ] ... [ 📋 Board (2026) 5 ] ... [ 🪑 Attendees ]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to have this automated? Otherwise, do we have to update this figure every time a new event is made?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No manual updates: the tabs count their rows at build time. Those numbers were only in a comment that draws the tab bar as an example, and I see how they read as something to maintain. They are now N in all five comments (83c39af).

…m comments

Two points from the review by @mesejo:

- The privacy policy says a person can object to a page built from our
  announcements, or to an event photograph, but not how. Both bullets now
  link to "Your rights", which says to write to pybcn@googlegroups.com.
- The comments that draw the tab bars of /talks/, /people/, and /events/
  carried the counts of the day (All 371, Speakers 356, ...), which read
  as numbers to update by hand. The tabs count their rows at build time;
  the comments now show N. The /people/ example also used the old role
  name, Organizer, and now says Event organizers.

bin/check-content: 0 errors, 79 warnings. bin/check-html-safety: PASS.
The anchor #your-rights is the id Hugo gives the heading "Your rights",
the same one the live policy has.
@mesejo
mesejo self-requested a review October 27, 2026 11:05
@DZPM
DZPM merged commit afff9c0 into edition Oct 27, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants