From 758f9de36dde570f619d4f56faf6d9d56144981d Mon Sep 17 00:00:00 2001 From: Nulo Date: Mon, 2 May 2022 18:55:35 +0000 Subject: [PATCH 01/21] Arreglar scroll al reordenar posts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Utilizaba https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded que es propietario. Ahora usa scrollIntoView siempre, configurado para que prácticamente siempre se pueda ver el post al reordenar. --- app/javascript/controllers/reorder_controller.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/javascript/controllers/reorder_controller.js b/app/javascript/controllers/reorder_controller.js index dca6e166..2cba4163 100644 --- a/app/javascript/controllers/reorder_controller.js +++ b/app/javascript/controllers/reorder_controller.js @@ -103,11 +103,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - if ("scrollIntoViewIfNeeded" in rows[0].row) { - rows[0].row.scrollIntoViewIfNeeded() - } else { - rows[0].row.scrollIntoView() - } + rows[0].row.scrollIntoView({ block: "center" }); } counter () { @@ -146,7 +142,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() + rows[0].row.scrollIntoView({ block: "center" }); } bottom (event) { @@ -167,7 +163,7 @@ export default class extends Controller { this.reorder() // Mantenemos el primero a la vista - rows[0].row.scrollIntoViewIfNeeded() + rows[0].row.scrollIntoView({ block: "center" }); } /* From abacabff8efa261f79855cdd22c6217806a096fe Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 18:39:56 -0300 Subject: [PATCH 02/21] fix: agregar licencia con layout --- app/services/site_service.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 22423bb8..436bc1c3 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -104,11 +104,10 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do def add_licencia(lang:) params = ActionController::Parameters.new( post: { + layout: 'license', lang: lang, title: site.licencia.name, description: I18n.t('sites.form.licencia.title'), - author: %w[Sutty], - permalink: "#{I18n.t('activerecord.models.licencia').downcase}/", content: CommonMarker.render_html(site.licencia.deed) } ) From 46c20cae7de41225b63ba5ff44eb7e5484a0e4ab Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 18:41:12 -0300 Subject: [PATCH 03/21] feat: no agregar licencia si la plantilla no lo soporta --- app/services/site_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 436bc1c3..87a08652 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -92,6 +92,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Crea la licencia del sitio para cada locale disponible en el sitio def add_licencias + return unless site.layout? :license + site.locales.each do |locale| next unless I18n.available_locales.include? locale From 0b353466a4c8113ed7c3fd57bed9f622ca298643 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 18:43:20 -0300 Subject: [PATCH 04/21] fix: solo cambiar la licencia si existe una #159 --- app/services/site_service.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 87a08652..b4fa2fa0 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -119,18 +119,14 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Encuentra la licencia a partir de su enlace permanente y le cambia # el contenido - # - # TODO: Crear un layout específico para licencias así es más certera - # la búsqueda. def change_licencias site.locales.each do |locale| next unless I18n.available_locales.include? locale Mobility.with_locale(locale) do - permalink = "#{I18n.t('activerecord.models.licencia').downcase}/" - post = site.posts(lang: locale).find_by(permalink: permalink) + post = site.posts(lang: locale).find_by(layout: 'license') - post ? change_licencia(post: post) : add_licencia(lang: locale) + change_licencia(post: post) if post end end end From 7b68bc15692ba4032e7ec9b660f6fc624512250d Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 18:45:41 -0300 Subject: [PATCH 05/21] =?UTF-8?q?fix:=20crear=20las=20licencias=20despu?= =?UTF-8?q?=C3=A9s=20de=20crear=20el=20t=C3=ADtulo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit y los commits también se harían en el idioma de le usuarie --- app/services/site_service.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index b4fa2fa0..e98d2487 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -14,11 +14,10 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do site.save && site.config.write && - commit_config(action: :create) + commit_config(action: :create) && + add_licencias end - add_licencias - site end @@ -27,11 +26,10 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do site.update(params) && site.config.write && - commit_config(action: :update) + commit_config(action: :update) && + change_licencias end - change_licencias - site end From ddd2bc07ff62b24745e74af4d6ce7284263e8117 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:04:15 -0300 Subject: [PATCH 06/21] =?UTF-8?q?feat:=20incorporar=20los=20c=C3=B3digos?= =?UTF-8?q?=20de=20conducta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/code_of_conduct.rb | 14 + app/services/site_service.rb | 34 +- config/initializers/inflections.rb | 4 + .../20230322214924_add_code_of_conduct.rb | 22 + db/seeds/codes_of_conduct.yml | 613 ++++++++++++++++++ 5 files changed, 686 insertions(+), 1 deletion(-) create mode 100644 app/models/code_of_conduct.rb create mode 100644 db/migrate/20230322214924_add_code_of_conduct.rb create mode 100644 db/seeds/codes_of_conduct.yml diff --git a/app/models/code_of_conduct.rb b/app/models/code_of_conduct.rb new file mode 100644 index 00000000..87c24c7f --- /dev/null +++ b/app/models/code_of_conduct.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Códigos de conducta +class CodeOfConduct < ApplicationRecord + extend Mobility + + translates :title, type: :string, locale_accessors: true + translates :description, type: :text, locale_accessors: true + translates :content, type: :text, locale_accessors: true + + validates :title, presence: true, uniqueness: true + validates :description, presence: true + validates :content, presence: true +end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index e98d2487..19b95302 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -15,7 +15,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.save && site.config.write && commit_config(action: :create) && - add_licencias + add_licencias && + add_code_of_conduct end site @@ -141,10 +142,41 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do params: params).update end + def add_code_of_conduct + # TODO: soportar más códigos de conducta + coc = CodeOfConduct.first + + with_all_locales do |locale| + params = ActionController::Parameters.new( + post: { + layout: 'code_of_conduct', + lang: locale.to_s, + title: coc.title, + description: coc.description, + content: CommonMarker.render_html(coc.content) + } + ) + + PostService.new(site: site, usuarie: usuarie, params: params).create + end + end + # Crea los deploys necesarios para sincronizar a otros nodos de Sutty def sync_nodes Rails.application.nodes.each do |node| site.deploys.build(type: 'DeployRsync', destination: "sutty@#{node}:#{site.hostname}") end end + + private + + def with_all_locales(&block) + site.locales.each do |locale| + next unless I18n.available_locales.include? locale + + Mobility.with_locale(locale) do + yield locale + end + end + end end diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 0e18b987..46cb9d78 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -13,6 +13,8 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.singular 'roles', 'rol' inflect.plural 'rollup', 'rollups' inflect.singular 'rollups', 'rollup' + inflect.plural 'code_of_conduct', 'codes_of_conduct' + inflect.singular 'codes_of_conduct', 'code_of_conduct' end ActiveSupport::Inflector.inflections(:es) do |inflect| @@ -28,4 +30,6 @@ ActiveSupport::Inflector.inflections(:es) do |inflect| inflect.singular 'licencias', 'licencia' inflect.plural 'rollup', 'rollups' inflect.singular 'rollups', 'rollup' + inflect.plural 'code_of_conduct', 'codes_of_conduct' + inflect.singular 'codes_of_conduct', 'code_of_conduct' end diff --git a/db/migrate/20230322214924_add_code_of_conduct.rb b/db/migrate/20230322214924_add_code_of_conduct.rb new file mode 100644 index 00000000..f859b08c --- /dev/null +++ b/db/migrate/20230322214924_add_code_of_conduct.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Crea códigos de conducta +class AddCodeOfConduct < ActiveRecord::Migration[6.1] + def up + create_table :codes_of_conduct do |t| + t.timestamps + t.string :title + t.text :description + t.text :content + end + + # XXX: En lugar de ponerlo en las seeds + YAML.safe_load(File.read('db/seeds/codes_of_conduct.yml')).each do |coc| + CodeOfConduct.new(**coc).save! + end + end + + def down + drop_table :codes_of_conduct + end +end diff --git a/db/seeds/codes_of_conduct.yml b/db/seeds/codes_of_conduct.yml new file mode 100644 index 00000000..64582072 --- /dev/null +++ b/db/seeds/codes_of_conduct.yml @@ -0,0 +1,613 @@ +--- +- title_en: "Codes for sharing" + title_es: "Códigos para compartir" + description_en: "Codes of conduct allow inclusive communities." + description_es: "Los códigos de convivencia nos permiten alojar comunidades inclusivas." + content_en: | + # Code for sharing + + > This code of conduct is based in "[Códigos para compartir, hackear, + > piratear en + > libertad](https://utopia.partidopirata.com.ar/zines/codigos_para_compartir.html)" + > published by [Partido Interdimensional + > Pirata](https://partidopirata.com.ar/). + + > We use gender neutral pronouns to include all peoples. In this sense, + > we encourage different forms, strategies and tools used to embody + > practices that aren't anthropocentric, sexist, cis-sexist in our + > language. + + ## Introduction + + This is an example code that strives to give a consensual frame to + enable asistance, permanence and confortable stay to everyone using and + inhabiting [Sutty](https://sutty.nl/), and to welcome new users and + potential allies as well. It sets the floor for desirable and + acceptable, and undesirable and intolerable conducts for its community. + You can use it with or without changes, adapting it to your activities. + This code is in permanent and collective mutation and feeds, copies and + inspires on the following sources: + + * + + * + + * + + * + + We strive to sustain and foment an open community, that invites and + attains participation from more people, in all their diversity. We know + that spaces related to computing and free software are mostly inhabited + by middle class cis white males, even when there's an acknowledgement of + the need to close the gender gap. In this sense, this is our little + contribution, made from collective practices on multiple dimentions, + reflections, readings, and experiences that grow every day. + + ## That everyone needs to be well treated + + Every being that we share space with deserves good treatment, respect + and compassion. Here we share basic criteria for introduction and care. + + ### Towards humans + + Everyone is deserving of care and greetings and we have a right to + assume good intentions from others. + + When we refer to other humans, we try to be careful and respectul + towards their gender identity. For this, these principles are useful: + + * Don't assume, judge or try to "interpret" the gender of others. + + * Don't use gender beforehand. It's related to the previous item, but + puts emphasis towards naturalized gendering behaviour (ie. assuming + someone wearing a dress uses female pronouns...). The proposal is to + discard them. + + * If a person explicits their pronouns and mode in which they want to be + referenced, we respect them, by listening and trying to use their + prefered pronouns. + + * When presentations don't include pronouns, we can ask respectfully + for prefered pronouns. But be careful! This question must be asked + to everyone, otherwise the "suspicion" is loaded towards a person, and + it can become a form of harrassment. + + * Do we need to know the gender of a person to relate with them? Maybe + a better practice is to evade gendering others. But if this means to + use "them" compulsively, some people may be made to feel bad. (For + instance, trans\* people who use female or male pronouns may feel + upset or outed when refering to them as "them", specially if they're + the only ones to be gendered like this in a group! + + * When in doubt, asking and apologizing respectfully is a good way of + being careful towards each other. + + ## Important points to guarantee our space from being expulsive + + **Listening to and between everyone in a caring climate** + + * Listen to what everyone has to say, being mindful that everyone has + something valuable to communicate. + + * For active listening, we prefer to ask first, before making judgement. + + * Sometimes being silent is a condition for others to be able to talk. + To listen is an exercise that requires practice. Also talking. + + * We're interested in what everyone has to say. If you're more trained + in participating, talking, and having opinions, take into account that + not everyone does. Give them space if they want to take it. But + remember that encouraging is not the same as pressuring! + + * We try to check and stop offensive practices to add to the respectful + climate. This doesn't mean to be submissive or to agree to + everything. At the least, it sets a floor of respect towards enabling + a dialogue when necessary. + + * It's at the very least disrepectful to repeat damaging behaviour when + it was already identified as such. It can make others unconfortable, + or hurt and expel them. We'll make this point every time that is + needed and tolerable. + + * We avoid this behaviour ourselves and we help others to notice their + own. + + * When raising attention becomes insufficient, we need to review this + agreements to keep the coexistence. This implies to act in accord to + them, and that this code can be revised and updated when deemed + necessary (there's no consensus). + + * One of the ways in which free software spaces can be and are expulsive + is with attitudes that don't contemplate diversity in knowledges and + interlocutors. By appealing to technicisms, many comrades are kept + out of what's happening, and no one verifies if everyone is keeping up + with the conversation. + + Our fervent recommendation is to be attentive to this dynamic so we + can avoid or revert them. + + * The counter to the previous situation is "mansplaining": a cis-male + person assuming the authoritative place of knowledge to (over-)explain + everything to others, in a patronizing way and without taking into + account what others want to listen or not, to say, what already know + or do, etc. + + * We believe there's no "authoritative voice" to have an opinion and to + participate. Free culture is for everyone to share. + + * "Sharing is caring" v. "Google is your friend". Meritocracy and other + traditional codes in cyber-communities work against free culture. We + support the pirate culture that onboards ever more pirates to their + ships. We believe that culture is for everyone and we defy elitisms. + + * We don't assume that other people shares our likings, beliefs, class + position, sexuality, etc. We can be violent when we misread others. + We recommend to ask respectfully and to avoid comments or jokes that + can be hurtful to others. + + * We speak and act gently and inclusively. + + * We respect different points of view, experiences, beliefs, etc. and we + take them into account when we act collectively so it reflects in our + attitudes. + + * We welcome criticism, specially the constructive kind ;) + + * We focus in what's best for the community, without losing warmth, + respect and diversity amongst ourselves. + + * We show empathy toward others. We want to share and communicate. + + * It's useful to think everyone has different abilities, stories, + experiences... It's possible to not understand some comments. We try + to avoid acting in bad faith and to use every accessibility tool we + can. + + * The last item includes neurodiverse people and those that have + experienced trauma. Sometimes, sarcasm or irony is not well received + or understood by others. We take this into our strategies to include + everyone in our communications. Even more, if we think some topics + could be sensitive to others (memory-triggering, phobias, untolerable, + explicit violence or body images, etc.), we use content warnings (cw) + before what we wanted to share. For instance: "cw: comments about + sexual and physical violence". This allows everyone to opt in to the + content instead of being taken by surprise. + + * We're respectful of limits established by others (personal space, + physical contact, interaction mood, privacy, being photographed, etc.) + + * We want to and believe in welcoming more pirates! + + ## Consent for documenting and sharing in media + + * If you're going to take pictures or record video, ask consent from + people involved. + + * If there're minors, ask their responsible families. + + ## Our commitment against harassment + + In the interest of fomenting an open, diverse and welcoming community, + we contributors and admins make a commitment against harassment in our + projects and community for everyone, without regard of age, body + diversity, capacity, neuro-diversity, ethnicity, gender identity and + expression, experience level, nationality, physical appearance, + religion, sexual identity or orientation. + + Examples of unacceptable behaviour from participants: + + * Offensive comments about gender/s, gender identity and expression, + sexual orientation, capacity, mental sickness, neuro-(a)tipicality, + physical appearance, body size, ethnicity or religion. + + * Unwelcomed comments related to personal and life choices, including + amongst others, those related to food, health, children upbringing, + drug use and employment. + + * Insulting or despective comments and personal or political attacks. + **Trolling**. + + * Assuming others' gender. If you're in doubt, ask politely about + pronouns. Don't use the name(s) that people don't use anymore, use + the name, _nickname_ or pseudonym that they prefer. Do you really + need the name, ID number, biometric data, birth certificate of others? + + * Sexual comments, images or behaviour, unneeded or in spaces where they + weren't appropiate. + + * Unconsented physical contact or repeated after being asked to stop. + + * Threatening others. + + * Inciting violence towards others, including self-damage. + + * Deliberate intimidation. + + * Stalking. + + * To harass by photographing or recording without consent, including + uploading personal information to the Internet. + + * Interrupting a conversation constantly. + + * Making unwanted sexual comments. + + * Unappropiate patterns of social contact, like asking/assuming + inappropiate intimacy levels with others. + + * Trying to interact with a person after being asked not to. + + * Exposing deliberately any aspect of a person identity without consent, + except when necessary for protecting others against intentional abuse. + + * Making public any kind of private conversation. + + * Other kinds of conduct that can be considered inappropiate in an + environment of camaraderie. + + * Repeating attitudes that others find offensive or violatory of this + code. + + ## Consequences + + * Any person that has been asked to stop offensive behaviour is expected + to respond immediately, even when in disagreement. + + * Admins can take any action deemed necessary and adequate, including + expelling the person or removing their site without advertence. This + decision is taken by consensus between admins and is reserved for + extreme cases that compromise the community or the permanence of + others without feeling wronged or threatened. + + * Admins reserve the right to forbid participation to any future + activity or publication. + + As we mentioned before, this code is in permanent collective mutation. + It's main objective is to generate an inclusive and non-expulsive + environment that is also transparent and open without [missing + stairs](https://en.wikipedia.org/wiki/Missing_stair) ("the missing stair + from a house that everyone knows about but no one wants to take + responsibility for"). It's important to adapt it to different + activities and that it nurtures from contributions from its users. + Receiving your comments and input will help us to achieve this + objective. + + ## Let's keep in contact! + + Si pasaste por alguna situación que quieras compartir --te hayas animado + o no a decirlo en el momento--, podés ponerte en contacto con nosotres. + + Con respecto a quejas o avisos acerca de situaciones de violencia, + acoso, abuso o repetición de conductas que se advirtieron como + intolerables, tomamos la responsabilidad de tenerlas en cuenta y + trabajar en ellas para que el resultado sea el favorable al espíritu de + colectiva que elegimos y describimos aquí. Si bien consideramos que las + prácticas punitivistas no van con nosotres, nuestra decisión explícita + es escuchar a la persona que se manifiesta como violentada o víctima y + acompañarla. + + You can contact us if you were part of a situation you want to share + --even if you didn't pointed it in the moment. + + In regards to complaints or notices about violence, harassment, abuse or + repeated untolerable conducts, we take the responsibility of working on + them for a favorable result towards the collective spirit we defined + here. Even when we don't condone punitivist practices, our explicit + decision is for the victim to be listened and accompanied. + content_es: | + # Códigos para compartir + + > Este código de convivencia está basado en los "[Códigos para + > compartir, hackear, piratear en + > libertad](https://utopia.partidopirata.com.ar/zines/codigos_para_compartir.html)" + > publicados por el [Partido Interdimensional + > Pirata](https://partidopirata.com.ar/). + + > Utilizamos preferentemente la 'e' para referirnos a las personas en + > general. En ese sentido, alentamos las diferentes formas, estrategias + > y herramientas para incorporar prácticas no antropocéntricas, + > sexistas, ni cisexistas en la lengua. Otras alternativas que apoyamos + > --y eventualmente usamos-- son el uso del femenino, la letra e, arrobas, + > equis, asteriscos, etc. + + ## Introducción + + Este es un ejemplo de código que busca aportar un marco de consenso para + garantizar la asistencia, permanencia y cómoda estadía de todas las + personas que habitan y utilizan Sutty, así como para bienvenir a nueves + usuaries y potenciales aliades. Para esto, fija un piso de conductas + deseables, aceptables, indeseables y/o intolerables para la comunidad. + Podés usarlo sin cambios o modificarlo para adaptarlo a tus actividades. + Este código está en permanente mutación colectiva y se alimenta, copia e + inspira de las siguientes fuentes: + + * + + * + + * + + * + + Procuramos mantener y fomentar una comunidad abierta, que invite y logre + la participación de cada vez más personas, en toda su diversidad. + Sabemos que los espacios de Software Libre, informática, sistemas, etc. + son habitados mayormente por varones cis, blancos y de clase media, pese + al reconocimiento de la necesidad de eliminar la brecha de géneros. En + este sentido, este es nuestro pequeño aporte, hecho de prácticas + colectivas de múltiples dimensiones, reflexiones, lecturas, experiencias + que crecen día a día. + + ## Que todes les seres sean bien tratades + + Cada ser con el que compartamos el espacio es merecedore de buen trato, + respeto y compasión. En otras palabras, compartimos a continuación los + criterios básicos de presentación y cuidados. + + Para les humanes + + Todes somos dignes de cuidados y de saludos y tenemos derecho a suponer + las buenas intenciones de le otre. + + Para referirnos a otres humanes, trataremos de ser cuidadoses y + respuestuoses de su identidad de género. Para ello, son útiles los + siguientes principios: + + * No presuponer, juzgar o "interpretar" el género de le otre. + + * No generizar de antemano. Se desprende del punto anterior, pero hace + especial énfasis en comportamientos naturalizados de generización (EJ: + presuponer que porque una persona usa un vestido se nombra en + femenino...). La propuesta es desecharlos. + + * Si la persona explicita sus pronombres y modos en que quiere ser + referenciade, lo respetamos, escuchando y procurando referirnos a elle + usando sus pronombres elegidos. + + * Si no se incluye en la presentación los pronombres preferidos, podemos + preguntar respetuosamente qué pronombres se usan. ¡Pero atención! Es + una pregunta que debe dirigirse a todes por igual, de lo contrario, + carga la "sospecha" sobre la persona señalada y puede resultar en una + forma de hostigamiento. + + * ¿Es necesario conocer el género de una persona para relacionarnos o + referirnos a ella? Quizás una buena práctica es evitar generizar para + todas las personas. Pero si esto implica el uso compulsivo de la "e" + para todes, puede ser que alguna persona se sienta molesta. (Por + ejemplo, las personas trans\* que se identifican en femenino o + masculino suelen sentirse molestas y "sacadas del clóset" u *outeadas* + si se refieren a ellas con la "e", ¡en especial si son las únicas en + ser generizadas de esta forma en un grupo!). + + * Ante cualquier duda, preguntar respetuosamente y disculparse + respetuosamente es una buena idea para ayudar a cuidarnos. + + ## Puntos importantes para garantizar que nuestro espacio no resulte expulsivo + + **Escucharnos a todas y entre todas en un clima de cuidados** + + * Escuchar lo que cada quien tiene para decir, conscientes de que todes + tenemos algo valioso para comunicar(nos). + + * Para la escucha activa, preferimos preguntar primero, en lugar de + hacer juicios. + + * Hacer silencio a veces es la condición para que otres puedan animarse + a hablar. Escuchar es un ejercicio que requiere práctica. También lo + es hablar. + + * Nos interesa lo que todes tengan para decir. Por lo tanto, si estás + más entrenade en el ejercicio de participar, hablar, opinar, tené en + cuenta que quizás haya otres que no lo estén tanto: darles el espacio + si quieren tomarlo. ¡Pero recordá que incentivar no es lo mismo que + presionar! + + * Tratamos de revisar y discontinuar alguna práctica que pueda haber + resultado ofensiva, para sumar al clima de respeto. Sin embargo, esto + no significa "bajar la cabeza" o estar necesariamente de acuerdo. Al + menos, fija un piso de respeto para comenzar un diálogo en el caso en + que sea necesario. + + * Es --al menos-- una falta de respeto repetir un comportamiento dañino + que ya se identificó como tal. Puede incomodar, lastimar y expulsar a + otres, por lo que preferimos llamar la atención sobre este punto todas + las veces que sea necesario y tolerable. + + * Evitamos esto nosotres y ayudamos a otres a darse cuenta cuando lo + están haciendo. + + * En los casos en los que los llamados de atención resulten + insuficientes, hemos de revisar estos acuerdos para sostener la + convivencia. Eso implica actuar de acuerdo a ellos. Y también que + estos códigos pueden ser revisados y actualizados en caso de que se + considere necesario (deje de haber consenso). + + * Una manera en la que los espacios de Software Libre y tecnologías + pueden y suelen ser expulsivos es mediante actitudes que no contemplan + la diversidad de saberes e interlocutor\*s. So pretexto de incluir + tecnicismos, muches compañeres quedan al margen de lo que está + sucediendo, muchas veces, sin que nadie tenga la mínima delicadeza de + verificar que todes estén siguiendo la conversación. + + Recomendamos fervientemente estar atentes a estas dinámicas para poder + evitarlas y/o revertirlas. + + * La otra cara de la situación anterior es el famoso _mansplaining_: un + tipo cis poniéndose en el lugar de la autoridad del saber para + (sobre-)explicar todo a le otre, de manera paternalista y sin tener en + cuenta lo que le otre quiere o no escuchar, decir, lo que sabe o hace, + etc. + + * Creemos que no hace falta ser "una voz autorizada" para opinar y + participar. La cultura libre se comparte entre todes. + + * "Compartir es bueno" vs. "Google es tu amigo". La meritocracia y + ciertos códigos tradicionales de ciertas ciber-comunidades suelen + operar de manera contraria a la propuesta de la cultura libre de + compartir. Apoyamos la cultura piratil que suma más piratas a los + barcos. Creemos que la cultura es para todes y desafiamos las + prácticas elitistas. + + * No damos por sentado que la persona con la que estamos interactuando + comparte gustos, creencias, pertenencias de clase, sexualidad, etc. + Podemos ser violentes si hacemos una lectura equivocada de le otre. + Recomendamos siempre preguntar de manera respetuosa y evitar + comentarios o chistes que puedan herir a les otres. + + * Usamos lenguaje amable e inclusivo y mostramos conductas amables e + inclusivas. + + * Respetamos los diferentes puntos de vista, experiencias, creencias, + etc. y lo tenemos en cuenta cuando estamos en grupo para verlo + reflejado en nuestras actitudes. + + * Aceptamos las críticas. En especial las constructivas ;) + + * Nos enfocamos en lo que es mejor para la comunidad, sin por ello + perder de vista la calidez, el respeto y la diversidad entre cada une + de nosotres. + + * Mostramos empatía con les otres. Queremos comunicarnos y compartir. + + * Es útil tener en cuenta que las personas tenemos capacidades, + historias, recorridos... diferentes. Es posible que algunos + comentarios no sean comprendidos. Trataremos de evitar la mala fe y + sumar todas las herramientas de accesibilidad para todas las personas. + + * El punto anterior incluye a personas neurodiversas y con experiencias + de trauma. A veces el sarcasmo o la ironía no es bien recibido o + comprendido por todes. Será útil tenerlo en cuenta para buscar + estrategias que no excluyan a las personas de nuestros intercambios. + Por otro lado, si creemos que determinados temas pueden ser sensibles + (desencadenantes de recuerdos, fobias, difíciles de tolerar o cargados + de violencia o imágenes corporales muy explícitas, por ejemplo) para + algunas personas y nos valemos de las advertencias de contenido o + _content warning_ (cw) (ej: "cw: comentarios de violencia sexual y + violencia física") antes del contenido a introducir. Esto permite que + cada cual pueda elegir si acceder o no a esos contenidos y que no le + tomen por sorpresa. + + * Respetamos los límites que establecen otras personas (espacio + personal, contacto físico, ganas de interactuar, no querer dar datos + de contacto o ser fotografiades, etc.) + + * ¡Queremos y (creemos) en sumar piratas! + + ## Consentimiento para documentar o compartir en medios + + * Si vas a publicar video o fotos, obtené el consentimiento de las + personas. + + * Si hay menores, consultalo con su familia responsable. + + ## Nuestro compromiso contra el acoso + + En el interés de fomentar una comunidad abierta, diversa y hospitalaria, + nosotres como contribuyentes y administradores nos comprometemos a hacer + de la participación en nuestro proyecto y nuestra comunidad una + experiencia libre de acoso para todes, independientemente de la edad, + diversidad corporal, capacidades, neuro-diversidad, etnia, identidad y + expresión de género, nivel de experiencia, nacionalidad, apariencia + física, raza, religión, identidad u orientación sexual y otras. + + Ejemplos de comportamiento inaceptable por parte de participantes: + + * Comentarios ofensivos relacionados con el/los género/s, la identidad + y expresión de género, la orientación sexual, las capacidades, las + enfermedades mentales, la neuro(a)tipicalidad, la apariencia física, + el tamaño corporal, la raza o la religión. + + * Comentarios indeseados relacionados con las elecciones y las prácticas + de estilo de vida de una persona, incluidas, entre otras, las + relacionadas con alimentos, salud, crianza de les hijes, drogas y + empleo. + + * Comentarios insultantes o despectivos (_trolling_) y ataques + personales o políticos. + + * Dar por sentado el género de las demás personas. En caso de duda, + preguntá educadamente por los pronombres. No uses nombres con los que + las personas no se identifican, usá el nombre, _nickname_ o apodo que + hayan elegido (¿Realmente necesitás el nombre y el número de DNI, + datos biométricos, carta natal, etc.?). + + * Comentarios, imágenes o comportamientos sexuales innecesarios o fuera + de lugar en espacios en los que no son apropiados. + + * Contacto físico sin consentimiento o reiterado tras un pedido de cese. + En el mismo sentido, invasión del espacio corporal (y espacios en + general). + + * Amenazas contra otras personas. + + * Incitación a la violencia contra otra persona, que también incluye + alentar a una persona a autolesionarse. + + * Intimidación deliberada. + + * Acechar (_stalkear_) o perseguir. + + * Acosar fotografiando o grabando sin consentimiento, incluyendo también + subir información personal a Internet sobre alguien para acosarle. + + * Interrumpir constantemente en una conversación. + + * Hacer comentarios sexuales indeseados. + + * Patrones de contacto social inapropiados, como por ejemplo + pedir/suponer niveles de intimidad inapropiados con les demás. + + * Seguir tratando de entablar conversación con una persona cuando se te + pidió que no lo hagas. + + * Divulgar deliberadamente cualquier aspecto de la identidad de una + persona sin su consentimiento, excepto que sea necesario para proteger + a otras personas de abuso intencional. + + * Hacer pública una conversación privada de cualquier tipo. + + * Otros tipos de conducta que pudieran considerarse inapropiadas en un + entorno de camaradería. + + * Reiteración de actitudes que les participantes señalen como ofensivas + o violatorias de este código. + + ## Consecuencias + + * Se espera que la persona a la que se la haya pedido que cese un + comportamiento que infringe este código acate el pedido de forma + inmediata, incluso si no está de acuerdo con este. + + * Les administradores pueden tomar cualquier acción que juzguen + necesaria y adecuada, incluyendo expulsar a la persona o dar de baja + sus sitios sin advertencia. Esta decisión la toman les administradores + en consenso y se reserva para casos extremos que comprometan la + continuidad de la comunidad o bien la posibilidad de permanencia en + ella de otres participantes sin sentirse agraviades o amenazades. + + * Les administradores se reservan el derecho a prohibir la asistencia a + cualquier actividad futura o publicación de sitios. + + Como mencionamos antes, este código está en permanente mutación + colectiva. El objetivo principal es generar un ambiente inclusivo y no + expulsivo, un ambiente transparente y abierto en el que no haya + escalones faltantes ("el escalón que falta en la escalera y todo el + mundo sabe y avisa pero nadie se quiere hacer cargo"). Es importante que + se adapte a las actividades y se nutra de las contribuciones de les + usuaries. Recibir tus comentarios y aportes nos ayudará a cumplir con + su objetivo principal. + + ## ¡Sigamos en contacto! + + Si pasaste por alguna situación que quieras compartir --te hayas animado + o no a decirlo en el momento--, podés ponerte en contacto con nosotres. + + Con respecto a quejas o avisos acerca de situaciones de violencia, + acoso, abuso o repetición de conductas que se advirtieron como + intolerables, tomamos la responsabilidad de tenerlas en cuenta y + trabajar en ellas para que el resultado sea el favorable al espíritu de + colectiva que elegimos y describimos aquí. Si bien consideramos que las + prácticas punitivistas no van con nosotres, nuestra decisión explícita + es escuchar a la persona que se manifiesta como violentada o víctima y + acompañarla. From 3f3ef0041092c06ade35df5a0b278a4e79fc976c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:06:57 -0300 Subject: [PATCH 07/21] =?UTF-8?q?fix:=20solo=20crear=20el=20c=C3=B3digo=20?= =?UTF-8?q?de=20conducta=20si=20la=20plantilla=20lo=20soporta?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit como fallback usamos page --- app/services/site_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 19b95302..e0fe17cd 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -143,13 +143,15 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do end def add_code_of_conduct + return unless site.layout?(:code_of_conduct) || site.layout?(:page) + # TODO: soportar más códigos de conducta coc = CodeOfConduct.first with_all_locales do |locale| params = ActionController::Parameters.new( post: { - layout: 'code_of_conduct', + layout: site.layout?(:code_of_conduct) ? 'code_of_conduct' : 'page', lang: locale.to_s, title: coc.title, description: coc.description, From 89ef2959e3c93a889677c3051a6987712a3434af Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:21:52 -0300 Subject: [PATCH 08/21] feat: usar un slug sino cuando cambia la licencia queda con la url de la anterior --- app/services/site_service.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index e0fe17cd..225c6292 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -106,6 +106,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do params = ActionController::Parameters.new( post: { layout: 'license', + slug: Jekyll::Utils.slugify(I18n.t('activerecord.models.licencia')), lang: lang, title: site.licencia.name, description: I18n.t('sites.form.licencia.title'), From e25b4858a01df490a66e5c818c0676828e45d539 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:23:51 -0300 Subject: [PATCH 09/21] fix: no cambiar las licencias si el sitio no las soporta --- app/services/site_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 225c6292..e4793453 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -120,6 +120,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Encuentra la licencia a partir de su enlace permanente y le cambia # el contenido def change_licencias + return unless site.layout? :license + site.locales.each do |locale| next unless I18n.available_locales.include? locale From 368001b341bfa0b6891a15088625c615d6839098 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:32:52 -0300 Subject: [PATCH 10/21] =?UTF-8?q?fix:=20poder=20encadenar=20licencias=20co?= =?UTF-8?q?n=20c=C3=B3digos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 46 ++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index e4793453..47b532f4 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -90,18 +90,19 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do end # Crea la licencia del sitio para cada locale disponible en el sitio + # + # @return [Boolean] def add_licencias - return unless site.layout? :license + return true unless site.layout? :license - site.locales.each do |locale| - next unless I18n.available_locales.include? locale - - Mobility.with_locale(locale) do - add_licencia lang: locale - end - end + with_all_locales do |locale| + add_licencia lang: locale + end.compact.map(&:valid?).all? end + # Crea una licencia + # + # @return [Post] def add_licencia(lang:) params = ActionController::Parameters.new( post: { @@ -119,20 +120,22 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # Encuentra la licencia a partir de su enlace permanente y le cambia # el contenido + # + # @return [Boolean] def change_licencias - return unless site.layout? :license + return true unless site.layout? :license - site.locales.each do |locale| - next unless I18n.available_locales.include? locale + with_all_locales do |locale| + post = site.posts(lang: locale).find_by(layout: 'license') - Mobility.with_locale(locale) do - post = site.posts(lang: locale).find_by(layout: 'license') - - change_licencia(post: post) if post - end - end + change_licencia(post: post) if post + end.compact.map(&:valid?).all? end + # Cambia una licencia + # + # @param :post [Post] + # @return [Post] def change_licencia(post:) params = ActionController::Parameters.new( post: { @@ -145,8 +148,11 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do params: params).update end + # Agrega un código de conducta + # + # @return [Boolean] def add_code_of_conduct - return unless site.layout?(:code_of_conduct) || site.layout?(:page) + return true unless site.layout?(:code_of_conduct) || site.layout?(:page) # TODO: soportar más códigos de conducta coc = CodeOfConduct.first @@ -163,7 +169,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do ) PostService.new(site: site, usuarie: usuarie, params: params).create - end + end.compact.map(&:valid?).all? end # Crea los deploys necesarios para sincronizar a otros nodos de Sutty @@ -176,7 +182,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do private def with_all_locales(&block) - site.locales.each do |locale| + site.locales.map do |locale| next unless I18n.available_locales.include? locale Mobility.with_locale(locale) do From 136a9e3edba9f5fe719c072c4b020996e90a9a28 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:44:17 -0300 Subject: [PATCH 11/21] =?UTF-8?q?fix:=20traducir=20la=20descripci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 47b532f4..449db16a 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -110,7 +110,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do slug: Jekyll::Utils.slugify(I18n.t('activerecord.models.licencia')), lang: lang, title: site.licencia.name, - description: I18n.t('sites.form.licencia.title'), + description: site.licencia.description, content: CommonMarker.render_html(site.licencia.deed) } ) From caa4861d79172cf6e49dab6c0e5cade15abcf023 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 19:54:04 -0300 Subject: [PATCH 12/21] fix: poder pasar el slug como parametro como slug es un atributo privado, hay que asignarlo manualmente --- app/services/post_service.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/services/post_service.rb b/app/services/post_service.rb index e448bb4c..81ebe4a1 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -12,6 +12,10 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do post.usuaries << usuarie params[:post][:draft] = true if site.invitade? usuarie + params.require(:post).permit(:slug).tap do |p| + post.slug.value = p[:slug] if p[:slug].present? + end + commit(action: :created, file: update_related_posts) if post.update(post_params) # Devolver el post aunque no se haya salvado para poder rescatar los From 0263169074f7795ae719d074f9f90f7aa2163d5c Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 20:00:39 -0300 Subject: [PATCH 13/21] fix: devolver true aunque no haga falta modificar la configuracion --- app/models/site/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/site/config.rb b/app/models/site/config.rb index 3215277e..11277a19 100644 --- a/app/models/site/config.rb +++ b/app/models/site/config.rb @@ -31,7 +31,7 @@ class Site # Escribe los cambios en el repositorio def write - return if persisted? + return true if persisted? @saved = Site::Writer.new(site: site, file: path, content: content.to_yaml).save From 0817139032ad0a93d4618fa6bcc78e474a4212bb Mon Sep 17 00:00:00 2001 From: f Date: Wed, 22 Mar 2023 21:01:29 -0300 Subject: [PATCH 14/21] =?UTF-8?q?feat:=20agregar=20pol=C3=ADtica=20de=20pr?= =?UTF-8?q?ivacidad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/privacy_policy.rb | 14 +++ app/services/site_service.rb | 26 +++- config/initializers/inflections.rb | 4 + .../20230322231344_add_privacy_policy.rb | 22 ++++ db/seeds/privacy_policies.yml | 113 ++++++++++++++++++ 5 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 app/models/privacy_policy.rb create mode 100644 db/migrate/20230322231344_add_privacy_policy.rb create mode 100644 db/seeds/privacy_policies.yml diff --git a/app/models/privacy_policy.rb b/app/models/privacy_policy.rb new file mode 100644 index 00000000..8805daa9 --- /dev/null +++ b/app/models/privacy_policy.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# Políticas de privacidad +class PrivacyPolicy < ApplicationRecord + extend Mobility + + translates :title, type: :string, locale_accessors: true + translates :description, type: :text, locale_accessors: true + translates :content, type: :text, locale_accessors: true + + validates :title, presence: true, uniqueness: true + validates :description, presence: true + validates :content, presence: true +end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 449db16a..64b25297 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -16,7 +16,8 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.config.write && commit_config(action: :create) && add_licencias && - add_code_of_conduct + add_code_of_conduct && + add_privacy_policy end site @@ -172,6 +173,29 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do end.compact.map(&:valid?).all? end + # Agrega política de privacidad + # + # @return [Boolean] + def add_privacy_policy + return true unless site.layout?(:privacy_policy) || site.layout?(:page) + + pp = PrivacyPolicy.first + + with_all_locales do |locale| + params = ActionController::Parameters.new( + post: { + layout: site.layout?(:privacy_policy) ? 'privacy_policy' : 'page', + lang: locale.to_s, + title: pp.title, + description: pp.description, + content: CommonMarker.render_html(pp.content) + } + ) + + PostService.new(site: site, usuarie: usuarie, params: params).create + end.compact.map(&:valid?).all? + end + # Crea los deploys necesarios para sincronizar a otros nodos de Sutty def sync_nodes Rails.application.nodes.each do |node| diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 46cb9d78..6002ee65 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -15,6 +15,8 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.singular 'rollups', 'rollup' inflect.plural 'code_of_conduct', 'codes_of_conduct' inflect.singular 'codes_of_conduct', 'code_of_conduct' + inflect.plural 'privacy_policy', 'privacy_policies' + inflect.singular 'privacy_policies', 'privacy_policy' end ActiveSupport::Inflector.inflections(:es) do |inflect| @@ -32,4 +34,6 @@ ActiveSupport::Inflector.inflections(:es) do |inflect| inflect.singular 'rollups', 'rollup' inflect.plural 'code_of_conduct', 'codes_of_conduct' inflect.singular 'codes_of_conduct', 'code_of_conduct' + inflect.plural 'privacy_policy', 'privacy_policies' + inflect.singular 'privacy_policies', 'privacy_policy' end diff --git a/db/migrate/20230322231344_add_privacy_policy.rb b/db/migrate/20230322231344_add_privacy_policy.rb new file mode 100644 index 00000000..e0d7ae59 --- /dev/null +++ b/db/migrate/20230322231344_add_privacy_policy.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Agrega políticas de privacidad +class AddPrivacyPolicy < ActiveRecord::Migration[6.1] + def up + create_table :privacy_policies do |t| + t.timestamps + t.string :title + t.text :description + t.text :content + end + + # XXX: En lugar de ponerlo en las seeds + YAML.safe_load(File.read('db/seeds/privacy_policies.yml')).each do |pp| + PrivacyPolicy.new(**pp).save! + end + end + + def down + drop_table :privacy_policies + end +end diff --git a/db/seeds/privacy_policies.yml b/db/seeds/privacy_policies.yml new file mode 100644 index 00000000..98ce8379 --- /dev/null +++ b/db/seeds/privacy_policies.yml @@ -0,0 +1,113 @@ +--- +- title_en: "Privacy Policy" + title_es: "Políticas de privacidad" + description_en: "With what care does this site handles personal data of its users and visitors?" + description_es: "¿Cuáles son los cuidados de este sitio con respecto a sus usuaries y visitantes?" + content_en: | + > We use "them" as neutral pronoun to refer to people regardless of + > gender identity. + + This document details Sutty's privacy policy, including web site, + platform, other infrastructure (support channels, etc.) and web sites + generated by users. + + ## This is too long! + + * Sutty doesn't collect any kind of personal data. + + * Sutty may only collect statistical data that doesn't identify + individuals. + + ## Analytic data + + Sutty may only collect data for analytics (number of visits, duration, + etc.), not associated to personal data. + + Analytical data collected for every web site can only be used internally + by Sutty. Sutty doesn't share any data privately with any third + parties. Selected analytical data could be used publicly. + + Sutty doesn't recommend personal data collection in any way, but it + doesn't monitor if its users use third party services with their own + privacy policies. We recommend users and visitors to inform themselves + before using third parties analytics services. + + ## No personal data collection + + Sutty doesn't collect IP addresses from users nor visitors in any way. + + Sutty doesn't ask for personal data for registering user accounts in its + platform. + + Sutty only uses session "cookies" to identify users during their use of + the platform. It doesn't use "cookies" to identify visitors of web + sites hosted by Sutty. + + The only exception where Sutty could collect personal data is during + service payment. Digital safety measures will be taken to keep this + information and to discard it if possible after needed. + + Users will be notified when their personal data is removed. + + If users decide to host their web sites with third parties, they must + inform themselves about the corresponding privacy policies. Sutty only + recommends third parties with privacy policies compatible with these. + content_es: | + > Utilizamos la e como pronombre neutro para referirnos a personas + > independientemente de su identidad de género, por ejemplo “usuarie”. + + Este documento detalla la política de privacidad de Sutty, incluyendo + sitio web, plataforma de edición, infraestructura relacionada (salas de + chat, etc.) y sitios creados por sus usuaries a través de la plataforma, + en adelante "Sutty". + + ## ¡Esto es demasiado largo! + + Un resumen: + + * Sutty no recolecta datos personales de ningún tipo + + * Sutty solo recolectaría datos analíticos que no identifican a + personas + + ## Datos analíticos + + La única recolección de datos realizada por Sutty es con fines + analíticos (cantidad de visitas, duración, etc.), no asociados a datos + personales. + + Los datos analíticos recolectados por cada sitio podrán ser utilizados + internamente por Sutty. Sutty no comparte datos analíticos con + terceros en forma privada. Datos analíticos seleccionados podrán ser + utilizados públicamente. + + Sutty no recomienda la recolección de datos personales de ninguna forma, + pero no monitorea que les usuaries utilicen servicios de terceros con + sus propias políticas de privacidad. Recomendamos a les usuaries y + visitantes informarse antes de utilizar servicios de estadísticas de + terceros. + + ## No registro de datos personales + + Sutty no registra direcciones IP de usuaries ni de visitantes de ninguna + forma. + + Sutty no solicita datos personales para el registro de cuentas de + usuarie en su plataforma. + + Sutty solo utiliza “cookies” de sesión para identificar usuaries + mientras utilicen la plataforma. No se utilizan “cookies” para + identificar visitantes a los sitios alojados por Sutty. + + El único caso en el que Sutty podría solicitar datos personales es + durante el pago de servicios. Se tomarán medidas de seguridad digital + para salvaguardar esta información y descartar lo que sea posible una + vez que ya no sea necesaria. + + Se notificará a les usuaries cuando su información personal sea + eliminada. + + Si les usuaries deciden alojar sus sitios con terceros, deberán + informarse de las políticas de privacidad correspondientes. Sutty + recomienda servicios de terceros con políticas de privacidad coherentes + con estas. From d01f4ae5e2432b7f34835a1ca50e1629d8ba96c1 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 23 Mar 2023 16:53:06 -0300 Subject: [PATCH 15/21] =?UTF-8?q?fix:=20volver=20a=20leer=20el=20sitio=20d?= =?UTF-8?q?espu=C3=A9s=20de=20guardarlo=20#12755?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 64b25297..eaefca3a 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -15,6 +15,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.save && site.config.write && commit_config(action: :create) && + site.reset.nil? && add_licencias && add_code_of_conduct && add_privacy_policy @@ -29,6 +30,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.update(params) && site.config.write && commit_config(action: :update) && + site.reset.nil? && change_licencias end From 42b2549f09e5fe9b3f33d6c632995253155400da Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 13:46:30 -0300 Subject: [PATCH 16/21] =?UTF-8?q?feat:=20agregar=20una=20descripci=C3=B3n?= =?UTF-8?q?=20corta=20a=20la=20licencia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit que es lo que usan las plantillas como aviso de licencia --- app/services/site_service.rb | 2 +- ...5163802_add_short_description_to_licencias.rb | 16 ++++++++++++++++ db/seeds/licencias.yml | 6 ++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20230325163802_add_short_description_to_licencias.rb diff --git a/app/services/site_service.rb b/app/services/site_service.rb index eaefca3a..2719a26c 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -113,7 +113,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do slug: Jekyll::Utils.slugify(I18n.t('activerecord.models.licencia')), lang: lang, title: site.licencia.name, - description: site.licencia.description, + description: site.licencia.short_description, content: CommonMarker.render_html(site.licencia.deed) } ) diff --git a/db/migrate/20230325163802_add_short_description_to_licencias.rb b/db/migrate/20230325163802_add_short_description_to_licencias.rb new file mode 100644 index 00000000..efcc01e4 --- /dev/null +++ b/db/migrate/20230325163802_add_short_description_to_licencias.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Agrega descripciones cortas a las licencias +class AddShortDescriptionToLicencias < ActiveRecord::Migration[6.1] + def up + add_column :licencias, :short_description, :string + + YAML.safe_load_file('db/seeds/licencias.yml').each do |licencia| + Licencia.find_by_icons(licencia['icons']).update licencia + end + end + + def down + remove_column :licencias, :short_description + end +end diff --git a/db/seeds/licencias.yml b/db/seeds/licencias.yml index cbe3bace..c5e2886a 100644 --- a/db/seeds/licencias.yml +++ b/db/seeds/licencias.yml @@ -1,6 +1,8 @@ --- - name_en: 'Peer Production License' name_es: 'Licencia de Producción de Pares' + short_description_en: "This work is licensed under a Peer Production License" + short_description_es: "Esta obra está bajo una Licencia de Producción de Pares" icons: "/images/ppl.png" url_en: 'https://wiki.p2pfoundation.net/Peer_Production_License' url_es: 'https://endefensadelsl.org/ppl_es.html' @@ -100,6 +102,8 @@ hacerlo es enlazar a esta página. - icons: "/images/by.png" + short_description_en: "This work is licensed under a Creative Commons Attribution 4.0 International License." + short_description_es: "Esta obra está bajo una Licencia Creative Commons Atribución 4.0 Internacional." name_en: 'Creative Commons Attribution 4.0 International (CC BY 4.0)' description_en: "This license gives everyone the freedom to use, adapt, and redistribute the contents of your site by requiring @@ -194,6 +198,8 @@ - icons: "/images/sa.png" name_en: "Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)" name_es: "Creative Commons Atribución-CompartirIgual 4.0 Internacional (CC BY-SA 4.0)" + short_description_en: "This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License." + short_description_es: "Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional." url_en: 'https://creativecommons.org/licenses/by-sa/4.0/' url_es: 'https://creativecommons.org/licenses/by-sa/4.0/deed.es' description_en: "This license is the same as the CC-BY 4.0 but it adds From c62d0d3a7254779f728fd14c224e2dc56127082e Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 13:48:30 -0300 Subject: [PATCH 17/21] =?UTF-8?q?fixup!=20feat:=20agregar=20una=20descripc?= =?UTF-8?q?i=C3=B3n=20corta=20a=20la=20licencia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/licencia.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/licencia.rb b/app/models/licencia.rb index c0eb1c80..f0a542ef 100644 --- a/app/models/licencia.rb +++ b/app/models/licencia.rb @@ -7,6 +7,7 @@ class Licencia < ApplicationRecord translates :name, type: :string, locale_accessors: true translates :url, type: :string, locale_accessors: true translates :description, type: :text, locale_accessors: true + translates :short_description, type: :string, locale_accessors: true translates :deed, type: :text, locale_accessors: true has_many :sites @@ -14,5 +15,6 @@ class Licencia < ApplicationRecord validates :name, presence: true, uniqueness: true validates :url, presence: true validates :description, presence: true + validates :short_description, presence: true validates :deed, presence: true end From d44ca16f81ec09f39713a94ee74da2b28c8b91e0 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 25 Mar 2023 13:51:07 -0300 Subject: [PATCH 18/21] =?UTF-8?q?fix:=20cambiar=20la=20descripci=C3=B3n=20?= =?UTF-8?q?de=20la=20licencia=20tambi=C3=A9n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 2719a26c..ce596482 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -143,6 +143,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do params = ActionController::Parameters.new( post: { title: site.licencia.name, + description: site.licencia.short_description, content: CommonMarker.render_html(site.licencia.deed) } ) From 661655abb5d03c2d2e21072de8230a05e324dc28 Mon Sep 17 00:00:00 2001 From: f Date: Thu, 30 Mar 2023 13:51:09 -0300 Subject: [PATCH 19/21] =?UTF-8?q?fix:=20hacer=20el=20deploy=20cuando=20el?= =?UTF-8?q?=20sitio=20ya=20est=C3=A1=20guardado=20#12276?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/site_service.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 75577226..70824422 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -30,11 +30,10 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do site.reset.nil? && add_licencias && add_code_of_conduct && - add_privacy_policy + add_privacy_policy && + deploy end - deploy - site end From b7a27a87dd2879622f89d4102f4a4346aa7c17ac Mon Sep 17 00:00:00 2001 From: f Date: Mon, 3 Apr 2023 16:58:22 -0300 Subject: [PATCH 20/21] feat: cuando se modifica la licencia, considerarla personalizada --- app/models/licencia.rb | 4 ++++ app/services/post_service.rb | 12 ++++++++++++ app/views/sites/_form.haml | 1 + db/seeds/licencias.yml | 6 ++++++ 4 files changed, 23 insertions(+) diff --git a/app/models/licencia.rb b/app/models/licencia.rb index f0a542ef..351a8ae5 100644 --- a/app/models/licencia.rb +++ b/app/models/licencia.rb @@ -17,4 +17,8 @@ class Licencia < ApplicationRecord validates :description, presence: true validates :short_description, presence: true validates :deed, presence: true + + def custom? + url == 'custom' + end end diff --git a/app/services/post_service.rb b/app/services/post_service.rb index 81ebe4a1..f1b9f7c3 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -18,6 +18,8 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do commit(action: :created, file: update_related_posts) if post.update(post_params) + update_site_license! + # Devolver el post aunque no se haya salvado para poder rescatar los # errores post @@ -44,6 +46,8 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do # relacionados. commit(action: :updated, file: update_related_posts) if post.update(post_params) + update_site_license! + # Devolver el post aunque no se haya salvado para poder rescatar los # errores post @@ -137,4 +141,12 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do p.path.absolute if p.save(validate: false) end.compact << post.path.absolute end + + # Si les usuaries modifican o crean una licencia, considerarla + # personalizada en el panel. + def update_site_license! + if site.usuarie?(usuarie) && post.layout.name == :license + site.update licencia: Licencia.find_by_url('custom') + end + end end diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 9a044c7f..10f158c8 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -79,6 +79,7 @@ %h2= t('.licencia.title') %p.lead= t('.help.licencia') - Licencia.all.find_each do |licencia| + - next if licencia.custom? && site.licencia != licencia .row.license .col .media.mt-1 diff --git a/db/seeds/licencias.yml b/db/seeds/licencias.yml index c5e2886a..402e5d8b 100644 --- a/db/seeds/licencias.yml +++ b/db/seeds/licencias.yml @@ -1,4 +1,10 @@ --- +- name_en: "Custom license" + name_es: "Licencia personalizada" + url_en: "custom" + url_es: "custom" + description_en: "The license terms are provided by you." + description_es: "Los términos de la licencia fueron provistos por vos." - name_en: 'Peer Production License' name_es: 'Licencia de Producción de Pares' short_description_en: "This work is licensed under a Peer Production License" From 94d30ac12aebac141992747613f888b573f5f43f Mon Sep 17 00:00:00 2001 From: f Date: Mon, 3 Apr 2023 17:50:04 -0300 Subject: [PATCH 21/21] fixup! feat: cuando se modifica la licencia, considerarla personalizada --- app/models/licencia.rb | 2 +- app/services/post_service.rb | 4 ++-- app/services/site_service.rb | 2 ++ app/views/sites/_form.haml | 7 ++++--- db/seeds/licencias.yml | 9 +++++++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/models/licencia.rb b/app/models/licencia.rb index 351a8ae5..65009f46 100644 --- a/app/models/licencia.rb +++ b/app/models/licencia.rb @@ -19,6 +19,6 @@ class Licencia < ApplicationRecord validates :deed, presence: true def custom? - url == 'custom' + icons == 'custom' end end diff --git a/app/services/post_service.rb b/app/services/post_service.rb index f1b9f7c3..7b31867d 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -145,8 +145,8 @@ PostService = Struct.new(:site, :usuarie, :post, :params, keyword_init: true) do # Si les usuaries modifican o crean una licencia, considerarla # personalizada en el panel. def update_site_license! - if site.usuarie?(usuarie) && post.layout.name == :license - site.update licencia: Licencia.find_by_url('custom') + if site.usuarie?(usuarie) && post.layout.name == :license && !site.licencia.custom? + site.update licencia: Licencia.find_by_icons('custom') end end end diff --git a/app/services/site_service.rb b/app/services/site_service.rb index 70824422..5e1d5055 100644 --- a/app/services/site_service.rb +++ b/app/services/site_service.rb @@ -110,6 +110,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # @return [Boolean] def add_licencias return true unless site.layout? :license + return true if site.licencia.custom? with_all_locales do |locale| add_licencia lang: locale @@ -140,6 +141,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do # @return [Boolean] def change_licencias return true unless site.layout? :license + return true if site.licencia.custom? with_all_locales do |locale| post = site.posts(lang: locale).find_by(layout: 'license') diff --git a/app/views/sites/_form.haml b/app/views/sites/_form.haml index 10f158c8..137a40b0 100644 --- a/app/views/sites/_form.haml +++ b/app/views/sites/_form.haml @@ -83,7 +83,8 @@ .row.license .col .media.mt-1 - = image_tag licencia.icons, alt: licencia.name, class: 'mr-3 mt-4' + - unless licencia.custom? + = image_tag licencia.icons, alt: licencia.name, class: 'mr-3 mt-4' .media-body .custom-control.custom-radio = f.radio_button :licencia_id, licencia.id, @@ -94,8 +95,8 @@ = sanitize_markdown licencia.description, tags: %w[p a strong em ul ol li h1 h2 h3 h4 h5 h6] - = link_to t('.licencia.url'), licencia.url, - target: '_blank', class: 'btn' + - unless licencia.custom? + = link_to t('.licencia.url'), licencia.url, target: '_blank', class: 'btn', rel: 'noopener' %hr/ diff --git a/db/seeds/licencias.yml b/db/seeds/licencias.yml index 402e5d8b..f6b76296 100644 --- a/db/seeds/licencias.yml +++ b/db/seeds/licencias.yml @@ -1,10 +1,15 @@ --- - name_en: "Custom license" name_es: "Licencia personalizada" - url_en: "custom" - url_es: "custom" + url_en: "" + url_es: "" + icons: "custom" + short_description_en: "" + short_description_es: "" description_en: "The license terms are provided by you." description_es: "Los términos de la licencia fueron provistos por vos." + deed_en: "" + deed_es: "" - name_en: 'Peer Production License' name_es: 'Licencia de Producción de Pares' short_description_en: "This work is licensed under a Peer Production License"