Hilfe beim Design eines benutzerdefinierten Integrations-Plugins

Hallo zusammen! Ich recherchiere verschiedene Forum-Plattformen, um eine Community für brasilianische Competitive-Programmierer (CP) aufzubauen, aber es scheint, als hätte ich sie gefunden!

Eine Funktion, die ich auf diesem Forum gerne hätte, ist eine Integration mit Codeforces – einer Online-Plattform, die Wettbewerbe und Diskussionen rund um CP hostet. Innerhalb von Codeforces haben Teilnehmer eine Bewertung (Rating), die sich entsprechend ihrer Leistung in bewerteten Wettbewerben ändert. Ich möchte meinen Nutzern die Möglichkeit geben, ihre hart erarbeiteten Bewertungen in ihren Forum-Profilen anzuzeigen.

Das Erste, was dieses Plugin, das ich entwickeln möchte, tun müsste, ist also, dem Nutzer die Eingabe seines Codeforces-Namens zu ermöglichen und dann irgendwie zu authentifizieren, dass der Name zum Forennutzer gehört. Um das zu tun, überlege ich, das Custom Wizard Plugin zu verwenden, um nach dem Namen zu fragen, dann eine zufällige Zeichenfolge über die Codeforces Talks API zu senden, die der Nutzer korrekt eingeben muss, und wenn alles in Ordnung ist, seinen Namen in einem benutzerdefinierten Feld zu speichern. Klingt das vernünftig? Würden Sie es anders machen?

Nun, ich kenne meine [zukünftigen] Nutzer, schließlich bin ich selbst ein CPer! Sie würden es genießen, ihre Bewertung durch die Farbe ihres Forum-Namens anzuzeigen. Das heißt, wenn Sie eine Bewertung über 1400 haben, ist Ihr Name cyanfarben, bei über 1600 blau und so weiter.

Meine schnelle Recherche zur Anpassung der Namenfarben in Discourse führte mich zu folgender Lösung. Ich sollte für jede Bewertungskategorie eine Nutzergruppe erstellen und dann meine Nutzer dynamisch der richtigen Gruppe zuweisen. (Gibt es einen besseren/einfacheren Weg?)

Wenn der Nutzer also zunächst sein Codeforces-Konto mit seinem Profil verknüpft, könnte ich seine Bewertung abrufen und ihm die richtige Gruppe zuweisen (Specialist, Expert, Candidate Master, …, International Grandmaster). Die Bewertung kann sich jedoch schnell ändern, und ich möchte die Gruppe des Nutzers automatisch aktualisieren, wenn sich seine Bewertung ändert.

Nun habe ich einige Möglichkeiten, dies zu erreichen, und ich möchte Vorschläge, welcher Weg der richtige ist, sowie, wenn möglich, eine Anleitung zu Discourse-spezifischen Details:

  • Einen regelmäßig laufenden Job, der die individuelle Bewertung und Gruppe jedes Nutzers aktualisiert (viele externe Anfragen an die Codeforces-API)
  • Einen regelmäßig laufenden Job, der Wettbewerbe verarbeitet, sobald sie stattfinden. Da sich Bewertungen nur während eines Wettbewerbs ändern können, kann ich, wenn die Bewertungen der Nutzer initial konsistent sind, durch die Verarbeitung von Bewertungsänderungen, sobald sie eintreten, nur die geänderten Bewertungen aktualisieren und die Konsistenz mit einem einzigen externen API-Aufruf aufrechterhalten.
  • Einen benutzerdefinierten Rating- und Gruppen-Resolver. Ich müsste also die letzte Bewertungsrückholung speichern und beim nächsten GET rating/groups, falls die Bewertung veraltet ist, die Codeforces-API aufrufen und die Bewertung/Gruppen des Nutzers aktualisieren. Dies ist meine bevorzugte Lösung, da sie einfach erscheint und immer eventual consistency gewährleistet. Allerdings bin ich mir nicht sicher, wie ich dies umsetzen würde oder welche Konsequenzen das dynamische Entfernen und Hinzufügen einer Gruppe zu einem Nutzer hätte. Oder ob dies überhaupt als Plugin möglich ist.

Tja, ich entschuldige mich für den Textwall! Ich würde mich über jegliche Art von Input zu all dem freuen. Vielen Dank für Ihre Aufmerksamkeit.

Sobald Sie den Codeforces-Namen in einem user_custom_field gespeichert haben, ist es ganz einfach, bei jedem Login alle gewünschten Profilinformationen zu aktualisieren (Gruppen zuweisen, beliebige Profildaten von Codeforces in die benutzerdefinierten Felder übernehmen usw.).

Etwas in der Art:

after_initialize do
  DiscourseEvent.on(:user_logged_in) do |user|
    # Daten von Codeforces abrufen
    if codeforce_rating > 1400
      group = Group.find_by(name: group_1400)
      if group
        gu = GroupUser.find_by(group_id: group.id, user_id: user.id)
        GroupUser.create(group_id: group.id, user_id: user.id) unless gu
      end
    end
  end
end

Auf diese Weise ist es sehr einfach, und Sie aktualisieren die Daten nur für Personen, die tatsächlich in der Community aktiv sind.

Das ist wunderbar! Ich bin froh, dass ich mich vorher erkundigt habe, bevor ich etwas umgesetzt habe.

Vielen Dank!

Wenn alle Ihre Benutzer Codeforces-Benutzer sind, würde ich einen Single Sign-On implementieren (wobei Codeforces der Authentifizierungsanbieter ist). Auf diese Weise ist kein zusätzlicher Authentifizierungsschritt erforderlich, und Ihre Benutzer erhalten einen besseren Registrierungs- bzw. Authentifizierungsablauf. Sie könnten sogar Gruppen auf diese Weise synchronisieren!

Ich würde dies an der Quelle erledigen, also dort, wo Codeforces weiß, dass sich die Bewertung geändert hat, einen API-Aufruf an Discourse senden, um die Bewertung (oder eine andere vom Benutzer beeinflusste Eigenschaft) zu aktualisieren. Auf diese Weise bleibt alles stets auf dem neuesten Stand. Wenn Sie Dinge synchronisieren müssen, führt das Abrufen (Polling) früher oder später immer zu Problemen. Vermeiden Sie es daher, wo immer möglich, und nutzen Sie einen ereignisbasierten Ansatz.

Ich ging davon aus, dass die Nutzung von Codeforces als SSO-Master nicht möglich ist. Falls doch, solltest du das definitiv so machen!

@pfaffmans Annahme, dass es nicht möglich sei, Codeforces als Authentifizierungsanbieter zu nutzen, war korrekt. Codeforces wird im Wesentlichen von einer Person gewartet, und ich bezweifle, dass er etwas für etwas umsetzen würde, das sich noch in der Planungs- oder Finanzierungsphase befindet.

Ich stimme zu, dass Polling suboptimal ist! Deshalb scheint die vorgeschlagene Lösung, es abzufragen, wenn sich der Benutzer anmeldet, ein guter Kompromiss zwischen [dem Interesse des Benutzers an] Konsistenz und dem Vermeiden von zu vielen Anfragen an die Server von Codeforces, die Aufmerksamkeit erregen und möglicherweise zu einer Sperrung führen könnten, zu sein.

Wenn unser spezifischer Fall für die brasilianische Community erfolgreich ist und andere Communities versuchen, dasselbe zu tun, wird Mike (die eine Person, die für Codeforces verantwortlich ist) vielleicht etwas Ähnliches umsetzen.

Trotzdem vielen Dank für die Vorschläge! Ich werde sie im Hinterkopf behalten, wenn ich mich im Juni nächsten Jahres mit Mike treffe, um ihn zu überzeugen, Unterstützung zu leisten, und möglicherweise die Lösung zu optimieren, die unser Forum zu diesem Zeitpunkt verwenden könnte.