From 1853231f56525ba815ee61954e754c4ee8e55661 Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Thu, 6 May 2010 00:24:27 +0200 Subject: [PATCH 01/25] Localisation updates from translatewiki.net (2010-05-05) --- config/locales/de.yml | 14 ++++----- config/locales/fr.yml | 22 +++++++++++++ config/locales/hr.yml | 48 +++++++++++++++++++++++++++-- config/locales/ia.yml | 56 ++++++++++++++++++++++++++++++++++ config/locales/ru.yml | 12 +++++++- config/locales/vi.yml | 13 ++++++++ config/potlatch/locales/ca.yml | 1 + config/potlatch/locales/de.yml | 9 +++--- config/potlatch/locales/gl.yml | 11 ++++--- config/potlatch/locales/hr.yml | 11 ++++++- config/potlatch/locales/ru.yml | 1 + 11 files changed, 178 insertions(+), 20 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 7afe21744..5d61a478d 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -885,7 +885,7 @@ de: history_tooltip: Änderungen für diesen Bereich anzeigen history_zoom_alert: Du musst näher heranzoomen, um die Chronik zu sehen layouts: - copyright: Urheberrechtsinformation + Lizenz + copyright: Urheberrecht + Lizenz donate: Unterstütze die OpenStreetMap-Hardwarespendenaktion durch eine eigene {{link}}. donate_link_text: Spende edit: Bearbeiten @@ -919,7 +919,7 @@ de: make_a_donation: text: Spenden title: Unterstütze OpenStreetMap mit einer Geldspende - news_blog: News-Blog + news_blog: Neuigkeiten-Blog news_blog_tooltip: News-Blog über OpenStreetMap, freie geographische Daten, etc. osm_offline: Die OpenStreetMap-Datenbank ist im Moment wegen wichtiger Wartungsarbeiten nicht verfügbar. osm_read_only: Die OpenStreetMap-Datenbank ist im Moment wegen wichtiger Wartungsarbeiten im „Nur-Lesen-Modus“. @@ -937,14 +937,14 @@ de: welcome_user_link_tooltip: Eigene Benutzerseite license_page: foreign: - english_link: das englischsprachige Original - text: Für den Fall einer Abweichung zwischen der vorliegenden Übersetzung und {{english_original_link}}, ist die englischsprachige Seite maßgebend + english_link: dem englischsprachigen Original + text: Für den Fall einer Abweichung zwischen der vorliegenden Übersetzung und {{english_original_link}}, ist die englischsprachige Seite maßgebend. title: Über diese Übersetzung - legal_babble: "

Urheberrechtsinformation und Lizenz

\n\n

\n OpenStreetMap besteht aus freien Daten, die gemäß der Lizenz Creative Commons Attribution-ShareAlike 2.0 (CC-BY-SA) verfügbar sind.\n

\n

\n Es steht Dir frei unsere Daten und Karten zu kopieren, weiterzugeben, zu übermittelt sowie anzupassen, sofern Du OpenStreetMap und die daran Mitwirkenden angibst. Für den Fall, dass Du auf Basis unsere Daten und Karten Veränderungen vornimmst oder als Basis für weitere Bearbeitungen verwendest, kannst Du das Ergebnis auch nur gemäß der selben Lizenz weitergeben. Der vollständige Lizenztext ist unter Lizenz einsehbar und erläutert Deine Rechte und Pflichten.\n

\n\n

So ist auf die Urheberschaft von OpenStreetMap hinzuweisen

\n

\n Sofern Du Bilder von OpenStreetMap verwendest, so ist mindestens „© OpenStreetMap und Mitwirkende, CC-BY-SA“ anzugeben. Werden hingegen ausschließlich Geodaten genutzt, so ist mindestens „Geodaten © OpenStreetMap und Mitwirkende, CC-BY-SA“ anzugeben.\n

\n

\n Wo möglich muss ein Hyperlink auf OpenStreetMap http://www.openstreetmap.org/ und die Lizenz CC-BY-SA http://creativecommons.org/licenses/by-sa/2.0/ gesetzt werden. Für den Fall, dass Du ein Medium einsetzt, bei dem keine derartigen Verweise möglich sind (z. B. ein gedrucktes Buch), schlagen wir vor, dass Du Deine Leser auf www.openstreetmap.org und www.creativecommons.org verweist.\n

\n\n

Mehr hierzu in Erfahrung bringen

\n

\n Mehr dazu, wie unsere Daten verwendet werden können ist unter Häufige rechtliche Fragen nachzulesen.\n

\n

\n Die Bearbeiter von OpenStreetMap möchten wird darauf hinweisen, dass Sie keinesfalls Daten aus urheberrechtlich geschützten Quellen verwenden dürfen (z. B. Google Maps oder gedruckte Kartenwerke) ohne vorher die ausdrückliche Erlaubnis des Rechteinhabers erhalten zu haben.\n

\n

\n Obzwar OpenStreetMap aus freien Daten besteht, können wir Dritten keine kostenfreie Programmierschnittstelle (API) für Karten bereitstellen.\n \n Siehe hierzu die Richtlinie zur Nutzung einer API, die Richtlinie zur Nutzung von Kachelgrafiken und die Nutzungsrichtlinie bezüglich Daten von Nominatim.\n

\n\n

Unsere Mitwirkenden

\n

\n Die von uns verwendete Lizenz CC-BY-SA verlangt, dass Du „für das betreffende Medium oder Mittel angemessen, auf die ursprünglichen Bearbeiter hinweist.“ Einige an OpenStreetMap Mitwirkende verlangen keine über den Vermerk „OpenStreetMap und Mitwirkende“ hinausgehende Hinweise. Wo allerdings Daten von Nationalen Kartografierungsinstitutionen oder aus anderen umfangreichen Quellen einbezogen wurden, ist es sinnvoll, deren Lizenzhinweise direkt wiederzugeben oder auf Sie auf dieser Website zu verlinken.\n

\n\n\n\n

\n Die Einbeziehung von Daten bei OpenStreetMap impliziert nicht, das der ursprüngliche Datenlieferant OpenStreetMap unterstützt, Gewährleistung gibt noch Haftung übernimmt.\n

" + legal_babble: "

Urheberrecht und Lizenz

\n\n

\n OpenStreetMap besteht aus freien Daten, die gemäß der Lizenz Creative Commons Attribution-ShareAlike 2.0 (CC-BY-SA) verfügbar sind.\n

\n

\n Es steht Dir frei unsere Daten und Karten zu kopieren, weiterzugeben, zu übermittelt sowie anzupassen, sofern Du OpenStreetMap und die Mitwirkenden als Quelle angibst. Für den Fall, dass Du auf Basis unserer Daten und Karten Anpassungen vornimmst, oder sie als Basis für weitere Bearbeitungen verwendest, kannst Du das Ergebnis auch nur gemäß der selben Lizenz weitergeben. Der vollständige Lizenztext ist unter Lizenz einsehbar und erläutert Deine Rechte und Pflichten.\n

\n\n

So ist auf die Urheberschaft von OpenStreetMap hinzuweisen

\n

\n Sofern Du Bilder von OpenStreetMap verwendest, so ist mindestens „© OpenStreetMap und Mitwirkende, CC-BY-SA“ als Quelle anzugeben. Werden hingegen ausschließlich Geodaten genutzt, so ist mindestens „Geodaten © OpenStreetMap und Mitwirkende, CC-BY-SA“ anzugeben.\n

\n

\n Wo möglich, muss ein Hyperlink auf OpenStreetMap http://www.openstreetmap.org/ und die Lizenz CC-BY-SA http://creativecommons.org/licenses/by-sa/2.0/ gesetzt werden. Für den Fall, dass Du ein Medium einsetzt, bei dem keine derartigen Verweise möglich sind (z. B. ein gedrucktes Buch), schlagen wir vor, dass Du Deine Leser auf www.openstreetmap.org und www.creativecommons.org hinweist.\n

\n\n

Mehr hierzu in Erfahrung bringen

\n

\n Mehr dazu, wie unsere Daten verwendet werden können, ist unter Häufige rechtliche Fragen nachzulesen.\n

\n

\n Die Mitwirkenden von OpenStreetMap weisen wir darauf hin, dass Sie keinesfalls Daten aus urheberrechtlich geschützten Quellen verwenden dürfen (z. B. Google Maps oder gedruckte Kartenwerke), ohne vorher die ausdrückliche Erlaubnis des Rechteinhabers erhalten zu haben.\n

\n

\n Obzwar OpenStreetMap aus freien Daten besteht, können wir Dritten keine kostenfreie Programmierschnittstelle (API) für Karten bereitstellen.\n \n Siehe hierzu die Richtlinie zur Nutzung einer API, die Richtlinie zur Nutzung von Kachelgrafiken und die Nutzungsrichtlinie bezüglich Daten von Nominatim.\n

\n\n

Unsere Mitwirkenden

\n

\n Die von uns verwendete Lizenz CC-BY-SA verlangt, dass Du „für das betreffende Medium oder Mittel in angemessener Weise, auf die ursprünglichen Bearbeiter hinweist.“ Einige an OpenStreetMap Mitwirkende verlangen keine über den Vermerk „OpenStreetMap und Mitwirkende“ hinausgehende Hinweise. Wo allerdings Daten von nationalen Kartografierungsinstitutionen oder aus anderen umfangreichen Quellen einbezogen wurden, ist es sinnvoll, deren Lizenzhinweise direkt wiederzugeben oder auf diese auf dieser Website zu verlinken.\n

\n\n\n\n

\n Die Einbeziehung von Daten bei OpenStreetMap impliziert nicht, das der ursprüngliche Datenlieferant OpenStreetMap unterstützt, Gewährleistung gibt, noch Haftung übernimmt.\n

" native: mapping_link: mit dem Kartieren anfangen - native_link: THIS_LANGUAGE_NAME_HERE Sprachversion - text: Du befindest dich auf der Seite mit der englischsprachigen Version der Urheberrechtsinformationen. Du kannst zur {{native_link}} dieser Seite zurückkehren oder das Lesen der Urheberrechtsinformationen beenden und {{mapping_link}}. + native_link: deutschen Sprachversion + text: Du befindest Dich auf der Seite mit der englischsprachigen Version der Urheberrechts- und Lizensierungsinformationen. Du kannst zur {{native_link}} dieser Seite zurückkehren oder das Lesen der Urheberrechtsinformationen beenden und {{mapping_link}}. title: Über diese Seite message: delete: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index e4e217c8f..c7347646b 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -129,7 +129,13 @@ fr: navigation: all: next_changeset_tooltip: Groupe de modifications suivant + next_node_tooltip: Nœud suivant + next_relation_tooltip: Relation suivante + next_way_tooltip: Way suivant prev_changeset_tooltip: Groupe de modifications précédent + prev_node_tooltip: Nœud précédent + prev_relation_tooltip: Relation précédente + prev_way_tooltip: Way précédent user: name_changeset_tooltip: Voir les modifications par {{user}} next_changeset_tooltip: Modifications suivantes par {{user}} @@ -218,6 +224,10 @@ fr: zoom_or_select: Zoomer ou sélectionner une zone de la carte pour la visualiser tag_details: tags: "Balises :" + wiki_link: + key: La description du tag {{key}} sur le wiki + tag: La description du tag {{key}}={{value}} sur le wiki + wikipedia_link: L'article {{page}} sur Wikipedia timeout: sorry: Désolé, les données pour le type {{type}} avec l'id {{id}} prennent trop de temps à être récupérées. type: @@ -866,6 +876,7 @@ fr: history_tooltip: Voir les modifications dans cette zone history_zoom_alert: Vous devez zoomer pour voir l’historique des modifications layouts: + copyright: Copyright & Licence donate: Soutenez OpenStreetMap, {{link}} au fond pour améliorer le matériel. donate_link_text: participez edit: Modifier @@ -914,6 +925,17 @@ fr: view_tooltip: Afficher la carte welcome_user: Bienvenue, {{user_link}} welcome_user_link_tooltip: Votre page utilisateur + license_page: + foreign: + english_link: original en anglais + text: En cas de conflit entre cette page et la page {{english_original_link}}, la version anglaise prime + title: A propos de cette traduction + legal_babble: "

Copyright et licence

\n

\n OpenStreetMap est un ensemble de données ouvertes, disponibles sous la licence Creative\n Commons Attribution-ShareAlike 2.0 (CC-BY-SA).\n

\n

\n Vous êtes libre de copier, distribuer, transmettre et adapter nos cartes\n et données, à condition que vous créditiez OpenStreetMap et ses\n contributeurs. Si vous modifiez ou utilisez nos cartes ou données dans d'autres travaux,\n vous ne pouvez distribuer ceux-ci que sous la même licence. Le\n texte\n légal complet détaille vos droits et responsabilités.\n

\n\n

Comment créditer OpenStreetMap

\n

\n Si vous utilisez les images d'OpenStreetMap, nous demandons que votre\n crédit comporte au moins la mention “© les contributeurs d'OpenStreetMap\n CC-BY-SA”. Si vous n'utilisez que les données des cartes,\n nous demandons “Données de la carte © les contributeurs d'OpenStreetMap,\n CC-BY-SA”.\n

\n

\n Là où cela est possible, OpenStreetMap doit être un lien hypertexte vers http://www.openstreetmap.org/\n et CC-BY-SA vers http://creativecommons.org/licenses/by-sa/2.0/.\n Si vous utiliser un média qui ne permet pas de créer des liens (ex :\n un imprimé), nous suggérons que vous dirigiez vos lecteurs vers\n www.openstreetmap.org (peut-être en étendant\n ‘OpenStreetMap’ à l'adresse complète) et vers\n www.creativecommons.org.\n

\n\n

Plus d'informations

\n

\n Si vous voulez obtenir plus d'informations sur la réutilisation de nos données, lisez la FAQ légale.\n

\n

\n Nous rappelons aux contributeurs d'OSM qu'ils ne doivent jamais ajouter de données provenant\n de sources sous copyright (ex : Google Maps ou des cartes imprimées) sans\n autorisation explicite de la part des détenteurs du copyright.\n

\n

\n Bien qu'OpenStreetMap soit un ensemble de données ouvertes, nous ne pouvons pas fournir\n d'API libre de frais pour les développeurs tiers.\n\n Voyez nos règles d'utilisation de l'API,\n règles d'utilisation de la carte\n et règles d'utilisation de Nominatim.\n

\n\n

Nos contributeurs

\n

\n Notre licence CC-BY-SA nécessite que vous “donniez à l'auteur d'origine\n un crédit raisonnable selon le média que vous utilisez”.\n Les cartographes individuels d'OSM ne demandent pas\n d'autre crédit que “les contributeurs d'OpenStreetMap”,\n mais lorsque des données venant d'une agence nationale de cartographie\n ou autre source majeure ont été incluses dans OpenStreetMap,\n il peut être raisonnable de les créditer directement\n de la manière qu'ils demandent ou par un lien vers cette page.\n

\n\n\n\n\n\n

\n L'inclusion de données dans OpenStreetMap n'implique pas que les fournisseurs d'origine\n du contenu approuvent OpenStreetMap, ni ne fournissent, ne garantissent ou n'acceptent quelque lien que ce soit.\n

" + native: + mapping_link: commencer à ontribuer + native_link: version française + text: Vous lisez la version anglais de la page de copyright. Vous pouvez retourner à la {{native_link}} de cette page ou arrêter de lire cette page et {{mapping_link}}. + title: A propos de cette page message: delete: deleted: Message supprimé diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 150d64894..b64faf99e 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -128,7 +128,13 @@ hr: navigation: all: next_changeset_tooltip: Slijedeći changeset + next_node_tooltip: Sljedeća točka + next_relation_tooltip: Sljedeća relacija + next_way_tooltip: Sljedeći put prev_changeset_tooltip: Prethodni changeset + prev_node_tooltip: Prethodna točka + prev_relation_tooltip: Prethodna relacija + prev_way_tooltip: Prethodni put user: name_changeset_tooltip: "Prikaži promjene korisnika: {{user}}" next_changeset_tooltip: Slijedeća promjena od {{user}} @@ -217,6 +223,10 @@ hr: zoom_or_select: Zoomiraj ili izaberi područje karte za pregled tag_details: tags: "Oznake:" + wiki_link: + key: Opis wiki stranica za oznaku {{key}} (tag) + tag: Opis wiki stranica za oznaku {{key}}={{value}} (tag) + wikipedia_link: Članak o {{page}} na Wikipediji timeout: sorry: Žao mi je, podaci za {{type}} sa id {{id}}, predugo se čekaju. type: @@ -365,6 +375,7 @@ hr: paste_html: Zalijepi HTML za ubacivanje na webstranicu scale: Mjerilo too_large: + body: Ovo područje je preveliko da bi se izvezlo kao OpenStreetMap XML podaci. Molimo povećajte (zoom) ili odaberite manju površinu. heading: Područje je preveliko zoom: Zoom start_rjs: @@ -857,9 +868,14 @@ hr: cycle_map: Biciklistička karta noname: Bezimene ulice site: + edit_disabled_tooltip: Uvećajte za uređivanje karte + edit_tooltip: Uredi kartu edit_zoom_alert: Morate zoomirati da bi uređivali kartu + history_disabled_tooltip: Zoomirajte da biste vidjeli uređivanja za ovo područje + history_tooltip: Prikaži izmjene za ovo područje history_zoom_alert: Morate zoomirati da bi vidjeli povijest izmjena layouts: + copyright: Autorska prava & Dozvola donate: Podržite OpenStreetMap sa {{link}} Hardware Upgrade Fond. donate_link_text: donacije edit: Uredi @@ -881,6 +897,9 @@ hr: intro_1: OpenStreetMap je slobodna, promjenjiva karta cijelog svijeta. Napravili su je ljudi slični tebi. intro_2: OpenStreetMap omogućava pregledavanje, uređivanje i korištenje geografskih podataka u suradničkom načinu od bilo gdje sa Zemlje. intro_3: Smještaj OpenStreetMapa je ljubazno podržan od {{ucl}} i {{bytemark}}. Ostali podržavatelji projekta su navedeni u {{partners}}. + intro_3_bytemark: bytemarka + intro_3_partners: wiki + intro_3_ucl: UCL VR Centra license: title: OpenStreetMap podaci su objavljeni pod licencom Creative Commons Attribution-Share Alike 2.0 Generic License log_in: prijava @@ -908,6 +927,17 @@ hr: view_tooltip: Pogledaj na karti welcome_user: Dobrodošli, {{user_link}} welcome_user_link_tooltip: Tvoja korisnička stranica + license_page: + foreign: + english_link: Engleski izvornik + text: U slučaju konflikta između ove prevedene stranice i {{english_original_link}}, Engleski stranice imaju prednost + title: O ovom prijevodu + legal_babble: "

Autorska prava i Dozvola

\n

\n OpenStreetMap su otvoreni podaci, licencirani pod Creative\n Commons Attribution-ShareAlike 2.0 dozvolom (CC-BY-SA).\n

\n

\n Slobodni ste kopirati, distribuirati, prenositi i adaptirati naše karte\n i podatke, sve dok navodite OpenStreetMap kao izvor i doprinositelje. Ako izmjenite \n ili nadogradite naše karte ili podatke, možete distribuirati rezultate\n samo pod istom licencom. Potpuna tekst objašnjava prava i obaveze.\n

\n\n

Kako navoditi OpenStreetMap kao izvor

\n

\n Ako koristite slike OpenstreetMap karte, zahtjevamo da\n se navede najmanje “© OpenStreetMap\n contributors, CC-BY-SA”. Ako koristite samo podatke,\n zahtjevamo “Map data © OpenStreetMap contributors,\n CC-BY-SA”.\n

\n

\n Gdje je moguće, OpenStreetMap treba biti kao hyperlink na http://www.openstreetmap.org/\n and CC-BY-SA to http://creativecommons.org/licenses/by-sa/2.0/. Ako\n koristite medija gdje linkovi nisu mogući (npr. isprintane\n karte), predlažemo da uputite vaše čitatelje na\n www.openstreetmap.org (proširenjem na\n ‘OpenStreetMap’ za ovo punu adresu) i na\n www.creativecommons.org.\n

\n\n

Više o

\n

\n Čitajte više o korištenju naših podataka na Legal\n FAQ.\n

\n

\n OSM korisnici - doprinostielji se podsjećaju da nikada ne dodaju podakte iz bilo kojeg\n izvora zaštićenog autorskim pravima (npr. Google Maps ili tiskane karte) bez izričite dozvole\n vlasnik autorskih prava.\n

\n

\n Iako su OpenstreetMap otvoreni podaci, ne možemo pružiti\n besplatni API za kartu za ostale developere.\n\n Vidi našu Politiku korištenja API-a,\n Politiku korištenja pločica\n and Politiku korištenja Nominatim-a.\n

\n\n

Naši korisnici - doprinostielji

\n

\n Naša CC-BY-SA licenca zahtjeva od vas da “ navedete izvor Originala\n reazumno prema mediju ili načinima koje koristite”. \n Pojedini OSM maperi ne traže navođenje njih preko ili više od\n “OpenStreetMap korisnici - doprinostielja”, ali gdje su podaci\n iz nacionalne agencije za kartiranje ili nekog drugog glavnog izvora uključeni u\n OpenStreetMap, razumno je navesti i njih direktno\n navodeći ime ili link na njihovu stranicu.\n

\n\n\n\n\n\n

\n Uvrštenje podataka u OpenStreetMap ne podrazumjeva da se izvorni\n davatelj podataka podržava OpenStreetMap, pruža bilo kakovo jamstvo, ili \n prihvaća bilo kakve obveze.\n

" + native: + mapping_link: počnite kartirati + native_link: HRVATSKI verzija + text: Vi gledate englesku verziju stranice o autorskim pravima. Možete se vratiti na {{native_link}} ove stranice ili možete prestati čitati o autorskim pravima i {{mapping_link}}. + title: O ovoj stranici message: delete: deleted: Poruka obrisana @@ -939,12 +969,13 @@ hr: subject: Tema title: Pošalji poruku no_such_message: + body: Nažalost nema poruka s tim id. heading: Nema takve poruke title: Nema takve poruke no_such_user: body: Nažalost ne postoji korisnik s tim imenom. heading: Nema takvog korisnika - title: Nema takvog korisnika ili poruke + title: Nema takvog korisnika outbox: date: Datum inbox: dolazna pošta @@ -988,6 +1019,7 @@ hr: hopefully_you_1: Netko (nadam se ti) želio bi promjeniti njihove email adrese preko u hopefully_you_2: "{{server_url}} na {{new_address}}." friend_notification: + befriend_them: Također, možete ih dodati kao prijatelja na {{befriendurl}}. had_added_you: "{{user}} te je dodao kao prijatelja na OpenStreetMap-u." see_their_profile: Možeš vidjeti njihov profil na {{userurl}}. subject: "[OpenStreetMap] {{user}} te je dodao kao prijatelja" @@ -1320,14 +1352,21 @@ hr: trackable: Trackable-može se pratiti (prikazuje se kao anonimne, posložene točke sa vremenskom oznakom) user: account: + current email address: "Trenutna E-mail adresa:" + delete image: Uklonite trenutnu sliku email never displayed publicly: (nikada se ne prikazuje javno) flash update success: Korisničke informacije su uspješno ažurirane. flash update success confirm needed: Korisničke informacije su uspješno ažurirane. Provjerite email za porukom za potvrdu nove email adrese. home location: "Dom:" + image: "Slika:" + image size hint: (kvadratne slike od barem 100x100 pixela rade najbolje) + keep image: Zadržite trenutnu sliku latitude: "Geografska širina (Latitude):" longitude: "Geografska dužina (Longitude):" make edits public button: Napravi sve moje promjene javnim my settings: Moje postavke + new email address: "Nova E-mail adresa:" + new image: Dodajte sliku no home location: Niste unjeli lokaciju vašeg doma. preferred languages: "Željeni jezici:" profile description: "Opis profila:" @@ -1341,6 +1380,7 @@ hr: public editing note: heading: Javno uređivanje text: Trenutno su vaše izmjene anonimne i ljudi vam ne mogu poslati poruke ili vidjeti vašu lokaciju. Da bi pokazali vaše izmjene i dozvolili ljudima da vas kontaktiraju preko website-a, kliknite gumb ispod Od promjene 0.6 API-a, samo javni korisnici mogu uređivati karte. (saznajte zašto). + replace image: Zamijenite trenutnu sliku return to profile: Vrati se na profil save changes button: Snimi promjene title: Uredi korisnički račun @@ -1371,9 +1411,12 @@ hr: lost password link: Izgubljena lozinka? password: "Lozinka:" please login: Molimo prijavite se ili {{create_user_link}}. + remember: "Zapamti me:" title: Prijava logout: heading: Odjava iz OpenStreetMap + logout_button: Odjava + title: Odjava lost_password: email address: "Email adresa:" heading: Zaboravljena lozinka? @@ -1407,6 +1450,7 @@ hr: heading: Korisnik {{user}} ne postoji title: Nema takvog korisnika popup: + friend: Prijatelj nearby mapper: Obližnji maper your location: Vaša lokacija remove_friend: @@ -1451,7 +1495,7 @@ hr: nearby users: Drugi korisnici u blizini new diary entry: novi unos u dnevnik no friends: Nisi dodao niti jednog prijatelja. - no nearby users: Nema okolnih korisnika koji mapiraju. + no nearby users: Još uvijek nema drugih korisnika koji kartiraju-mapiraju u blizini. oauth settings: oauth postavke remove as friend: ukloni kao prijatelja role: diff --git a/config/locales/ia.yml b/config/locales/ia.yml index e72b4208f..9e82b2184 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -123,7 +123,13 @@ ia: navigation: all: next_changeset_tooltip: Gruppo de modificationes sequente + next_node_tooltip: Nodo sequente + next_relation_tooltip: Relation sequente + next_way_tooltip: Via sequente prev_changeset_tooltip: Gruppo de modificationes precedente + prev_node_tooltip: Nodo precedente + prev_relation_tooltip: Relation precedente + prev_way_tooltip: Via precedente user: name_changeset_tooltip: Vider modifications per {{user}} next_changeset_tooltip: Modification sequente per {{user}} @@ -212,6 +218,9 @@ ia: zoom_or_select: Face zoom avante o selige un area del carta a visualisar tag_details: tags: "Etiquettas:" + wiki_link: + key: Le pagina wiki que describe le etiquetta {{key}} + tag: Le pagina wiki que describe le etiquetta {{key}}={{value}} wikipedia_link: Le articulo {{page}} in Wikipedia timeout: sorry: Pardono, le datos pro le {{type}} con le ID {{id}} ha prendite troppo de tempore pro esser recuperate. @@ -500,6 +509,33 @@ ia: waste_basket: Corbe a papiro wifi: Accesso WiFi youth_centre: Centro pro le juventute + boundary: + administrative: Limite administrative + building: + apartments: Bloco de appartamentos + chapel: Cappella + church: Ecclesia + city_hall: Casa municipal + commercial: Edificio commercial + entrance: Entrata de edificio + faculty: Edificio de facultate + farm: Edificio agricole + flats: Appartamentos + garage: Garage + hospital: Edificio hospitalari + hotel: Hotel + house: Casa + industrial: Edificio industrial + public: Edificio public + retail: Magazin + school: Edificio de schola + stadium: Stadio + store: Magazin + terrace: Terrassa + tower: Turre + train_station: Station ferroviari + university: Edificio de universitate + "yes": Edificio highway: bridleway: Sentiero pro cavallos bus_guideway: Via guidate de autobus @@ -718,17 +754,26 @@ ia: viewpoint: Puncto de vista zoo: Zoo waterway: + boatyard: Cantier naval + canal: Canal + connector: Connexion aquatic + dam: Dica derelict_canal: Canal abandonate ditch: Fossato dock: Dock drain: Aquiero lock: Esclusa lock_gate: Porta de esclusa + mineral_spring: Fonte de aqua mineral mooring: Ammarrage rapids: Rapidos river: Fluvio/Riviera riverbank: Ripa de fluvio/riviera + stream: Rivo + wadi: Wadi + water_point: Puncto de aqua waterfall: Cascada + weir: Barrage javascripts: map: base: @@ -787,6 +832,17 @@ ia: view_tooltip: Vider le carta welcome_user: Benvenite, {{user_link}} welcome_user_link_tooltip: Tu pagina de usator + license_page: + foreign: + english_link: le original in anglese + text: In caso de un conflicto inter iste pagina traducite e {{english_original_link}}, le pagina in anglese prevalera. + title: A proposito de iste traduction + legal_babble: "

Copyright e Licentia

\n

\n OpenStreetMap es datos aperte, disponibile sub le licentia\n Creative\n Commons Attribution-ShareAlike 2.0 (CC-BY-SA).\n

\n

\n Vos es libere de copiar, distribuer, transmitter e adaptar nostre cartas\n e datos, a condition que vos da recognoscentia a OpenStreetMap e su\n contributores. Si vos altera o extende nostre cartas e datos, vos\n pote distribuer le resultato solmente sub le mesme licentia. Le\n complete codice\n legal explica vostre derectos e responsabilitates.\n

\n\n

Como dar recognoscentia a OpenStreetMap

\n

\n Si vos usa imagines del cartas de OpenStreetMap, nos requesta que\n vostre recognoscentia indica al minus “© Contributores de\n OpenStreetMap, CC-BY-SA”. Si vos usa solmente datos cartographic,\n nos requesta “Datos cartographic © Contributores de OpenStreetMap,\n CC-BY-SA”.\n

\n

\n Si possibile, le parola OpenStreetMap debe esser un hyperligamine a http://www.openstreetmap.org/\n e le termino CC-BY-SA debe ligar a http://creativecommons.org/licenses/by-sa/2.0/. Si\n vos usa un medio de communication in le qual le ligamines non es possibile (p.ex. un\n obra imprimite), nos suggere que vos dirige vostre lectores a\n www.openstreetmap.org (possibilemente per expander\n ‘OpenStreetMap’ a iste adresse complete) e a\n www.creativecommons.org.\n

\n\n

Pro saper plus

\n

\n Lege plus super le uso de nostre datos al FAQ\n Legal.\n

\n

\n Le contributores de OSM es recordate de nunquam adder datos de alcun\n fonte subjecte al derecto de autor (p.ex. Google Maps o cartas imprimite)\n sin explicite permission del titulares del derecto de autor.\n

\n

\n Ben que OpenStreetMap es datos aperte, nos non pote fornir un\n API cartographic gratuite pro altere disveloppatores.\n\n Vide nostre politica pro le uso del API,\n politica pro le uso de tegulas\n e politica pro le uso de Nominatim.\n

\n\n

Nostre contributores

\n

\n Nostre licentia CC-BY-SA require que vos “da al Autor\n Original recognoscentia rationabile pro le medio que Vos\n utilisa”. Le cartographos individual de OSM non requesta un\n recognoscentia excedente illo del “Contributores de\n OpenStreetMap”, sed ubi datos de un agentia cartographic\n national o altere fonte major ha essite includite in\n OpenStreetMap, il pote esser rationabile dar les recognoscentia per\n directemente reproducer lor recognoscentia o per ligar a illo in iste pagina.\n

\n\n\n\n\n\n

\n Le inclusion de datos in OpenStreetMap non implica que le fornitor\n original del datos indorsa OpenStreetMap, forni alcun garantia, o\n accepta alcun responsabilitate.\n

" + native: + mapping_link: comenciar le cartographia + native_link: version in interlingua + text: Tu vide nunc le version in anglese del pagina de copyright. Tu pote retornar al {{native_link}} de iste pagina o tu pote cessar de leger super copyright e {{mapping_link}}. + title: A proposito de iste pagina message: delete: deleted: Message delite diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 4a03b20c2..fe9d18a01 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -880,7 +880,7 @@ ru: history_tooltip: Просмотр правок в этой области history_zoom_alert: Необходимо увеличить масштаб карты, чтобы увидеть историю правок layouts: - copyright: Авт. право и лицензия + copyright: Авторское право и лицензия donate: Поддержите OpenStreetMap {{link}} в Фонд обновления оборудования. donate_link_text: пожертвованиями edit: Правка @@ -931,6 +931,16 @@ ru: view_tooltip: Посмотреть карту welcome_user: Добро пожаловать, {{user_link}} welcome_user_link_tooltip: Ваша страница пользователя + license_page: + foreign: + english_link: английского оригинала + text: В случае конфликта между этой переведённой страницей и {{english_original_link}}, английская страница должна иметь приоритет + title: Об этом переводе + native: + mapping_link: начать картографирование + native_link: русской версии + text: Вы просматриваете английскую версию страницы авторских прав. Вы можете вернуться к {{native_link}} этой страницы или можете прекратить чтение об авторских правах и {{mapping_link}}. + title: Об этой странице message: delete: deleted: Сообщение удалено diff --git a/config/locales/vi.yml b/config/locales/vi.yml index bc6809c90..5286cdd6c 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -2,6 +2,7 @@ # Exported from translatewiki.net # Export driver: syck # Author: Minh Nguyen +# Author: Ninomax vi: activerecord: attributes: @@ -123,7 +124,11 @@ vi: navigation: all: next_changeset_tooltip: Bộ thay đổi sau + next_node_tooltip: Node tiếp theo + next_way_tooltip: Đường tiếp theo prev_changeset_tooltip: Bộ thay đổi trước + prev_node_tooltip: Node trước + prev_relation_tooltip: Relation trước user: name_changeset_tooltip: Xem các đóng góp của {{user}} next_changeset_tooltip: Đóng góp sau của {{user}} @@ -422,6 +427,7 @@ vi: bench: Ghế bicycle_parking: Chỗ Đậu Xe đạp bicycle_rental: Chỗ Mướn Xe đạp + bus_station: Trạm xe bus cafe: Quán Cà phê car_rental: Chỗ Mướn Xe car_sharing: Chia sẻ Xe cộ @@ -466,6 +472,7 @@ vi: post_office: Bưu điện preschool: Trường Mầm non prison: Nhà tù + pub: Quán rượu public_market: Chợ phiên restaurant: Nhà hàng sauna: Nhà Tắm hơi @@ -797,6 +804,12 @@ vi: view_tooltip: Xem bản đồ welcome_user: Hoan nghênh, {{user_link}} welcome_user_link_tooltip: Trang cá nhân của bạn + license_page: + foreign: + english_link: nguyên bản tiếng Anh + text: Trong trường hợp có xung đột giữa trang dịch và trang {{english_original_link}}, trang tiếng Anh sẽ được ưu tiên + native: + title: Giới thiệu về trang này message: delete: deleted: Đã xóa thư diff --git a/config/potlatch/locales/ca.yml b/config/potlatch/locales/ca.yml index eccc3e953..624f7034b 100644 --- a/config/potlatch/locales/ca.yml +++ b/config/potlatch/locales/ca.yml @@ -132,6 +132,7 @@ ca: option_layer_ooc_scotland: "Regne Unit històric: Escòcia" option_layer_os_streetview: "UK: OS StreetView" option_layer_streets_haiti: "Haití: noms de carrers" + option_layer_surrey_air_survey: "Regne Unit: Mesurament aeri de Surrey" option_layer_tip: Escollir el fons a mostrar option_limitways: Avisar si hi ha molta càrrega de dades option_microblog_id: "Nom microblog:" diff --git a/config/potlatch/locales/de.yml b/config/potlatch/locales/de.yml index 90312ed08..e4f36fccb 100644 --- a/config/potlatch/locales/de.yml +++ b/config/potlatch/locales/de.yml @@ -136,12 +136,13 @@ de: option_layer_cycle_map: OSM - Radwanderkarte option_layer_maplint: OSM - Maplint (Fehler) option_layer_nearmap: "Australien: NearMap" - option_layer_ooc_25k: Historische UK Karten 1:25k - option_layer_ooc_7th: "UK historic: 7th" - option_layer_ooc_npe: "UK historic: NPE" - option_layer_ooc_scotland: "UK-Historisch: Schottland" + option_layer_ooc_25k: "UK (historisch): Karten 1:25k" + option_layer_ooc_7th: "UK (historisch): 7th" + option_layer_ooc_npe: "UK (historisch): NPE" + option_layer_ooc_scotland: "UK (historisch): Schottland" option_layer_os_streetview: "UK: OS StreetView" option_layer_streets_haiti: "Haiti: Straßenname" + option_layer_surrey_air_survey: "UK: Surrey Air Survey" option_layer_tip: Hintergrund auswählen option_limitways: Warnung wenn große Datenmenge geladen wird option_microblog_id: "Microblog Name:" diff --git a/config/potlatch/locales/gl.yml b/config/potlatch/locales/gl.yml index 54abd6047..1fbffb1c0 100644 --- a/config/potlatch/locales/gl.yml +++ b/config/potlatch/locales/gl.yml @@ -125,12 +125,13 @@ gl: option_layer_cycle_map: OSM - mapa cíclico option_layer_maplint: OSM - Maplint (erros) option_layer_nearmap: "Australia: NearMap" - option_layer_ooc_25k: "Historial UK: 1:25k" - option_layer_ooc_7th: "Historial UK: 7º" - option_layer_ooc_npe: "Historial UK: NPE" - option_layer_ooc_scotland: "RU histórico: Escocia" - option_layer_os_streetview: "RU: OS StreetView" + option_layer_ooc_25k: "Reino Unido histórico: 1:25k" + option_layer_ooc_7th: "Reino Unido histórico: 7º" + option_layer_ooc_npe: "Reino Unido histórico: NPE" + option_layer_ooc_scotland: "Reino Unido histórico: Escocia" + option_layer_os_streetview: "Reino Unido: OS StreetView" option_layer_streets_haiti: "Haití: nomes de rúas" + option_layer_surrey_air_survey: "Reino Unido: Enquisa aérea sobre Surrey" option_layer_tip: Escolla o fondo a mostrar option_limitways: Avisar ao cargar moitos datos option_microblog_id: "Nome do blogue de mensaxes curtas:" diff --git a/config/potlatch/locales/hr.yml b/config/potlatch/locales/hr.yml index ae9de0ad2..96dddff71 100644 --- a/config/potlatch/locales/hr.yml +++ b/config/potlatch/locales/hr.yml @@ -32,6 +32,7 @@ hr: advanced_tooltip: Napredne uređivačke akcije advanced_undelete: Vrati obrisano advice_bendy: Previše zavojito za izravnavanje (SHIFT za nasilno) + advice_conflict: Konflikt na serveru - možda ćete morati ponovno pokušati spremiti advice_deletingpoi: Brisanje POI (Z - poništi) advice_deletingway: Brisanje puta (poništi sa Z) advice_microblogged: $1 status je ažuriran @@ -89,6 +90,7 @@ hr: hint_saving: Spremanje podataka hint_saving_loading: učitavanje/spremanje podataka inspector: Inspektor + inspector_duplicate: "Duplikat od:" inspector_in_ways: U putevima inspector_latlon: "Lat $1\nLon $2" inspector_locked: Zaključan @@ -100,6 +102,7 @@ hr: inspector_way_connects_to_principal: Spaja se na $1 $2 i $3 drugi $4 inspector_way_nodes: $1 točke inspector_way_nodes_closed: $1 točaka (zatvoren) + loading: Učitavam... login_pwd: "Lozinka:" login_retry: Prijava na site nije prepoznata. Pokušajte ponovo. login_title: Ne mogu se prijaviti @@ -179,13 +182,19 @@ hr: prompt_microblog: Šalji na $1 ($2 ostalo) prompt_revertversion: "Vrati na prijašnju spremljenu verziju:" prompt_savechanges: Spremi promjene - prompt_taggedpoints: Neke točke na ovom putu su označene (Tags). Stvarno obrisati? + prompt_taggedpoints: Neke od točaka na tom putu su označene ili u relacijama. Želite izbrisati? prompt_track: Pretvori GPS trag u put prompt_unlock: Klik za otključavanje prompt_welcome: Dobrodošli na OpenStreetMap! retry: Pokušaj ponovo revert: Vrati na staro save: Spremi + tags_backtolist: Povratak na listu + tags_descriptions: Opisi '$1' + tags_findatag: Pronađi oznaku (tag) + tags_findtag: Pronađi oznaku (tag) + tags_matching: Popularne oznake koje odgovaraju '$1' + tags_typesearchterm: "Unesite riječ za pretragu:" tip_addrelation: Dodaj relaciji tip_addtag: Dodaj novu oznaku (Tag) tip_alert: Došlo je do greške - klikni za detalje diff --git a/config/potlatch/locales/ru.yml b/config/potlatch/locales/ru.yml index f041f125b..4c68721f6 100644 --- a/config/potlatch/locales/ru.yml +++ b/config/potlatch/locales/ru.yml @@ -142,6 +142,7 @@ ru: option_layer_os_streetview: "UK: OS StreetView" option_layer_osmarender: OSM - Osmarender option_layer_streets_haiti: "Гаити: названия улиц" + option_layer_surrey_air_survey: "UK: Surrey Air Survey" option_layer_tip: Выберите фон option_layer_yahoo: Yahoo! option_limitways: Предупрежд. когда много данных From d75c99b62d78edb12639d0a182eaecdc134feb99 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Thu, 6 May 2010 15:08:47 +0100 Subject: [PATCH 02/25] Update to OpenLayers 2.9.1 --- public/openlayers/OpenLayers.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/public/openlayers/OpenLayers.js b/public/openlayers/OpenLayers.js index ed9877653..fe7a99241 100644 --- a/public/openlayers/OpenLayers.js +++ b/public/openlayers/OpenLayers.js @@ -94,7 +94,7 @@ var OpenLayers={singleFile:true};(function(){var singleFile=(typeof OpenLayers== scriptLocation="";var isOL=new RegExp("(^|(.*?\\/))("+OpenLayers._scriptName+")(\\?|$)");var scripts=document.getElementsByTagName('script');for(var i=0,len=scripts.length;i";}else{var s=document.createElement("script");s.src=host+jsfiles[i];var h=document.getElementsByTagName("head").length?document.getElementsByTagName("head")[0]:document.body;h.appendChild(s);}} -if(docWrite){document.write(allScriptTags.join(""));}}})();OpenLayers.VERSION_NUMBER="$Revision: 10129 $";OpenLayers.String={startsWith:function(str,sub){return(str.indexOf(sub)==0);},contains:function(str,sub){return(str.indexOf(sub)!=-1);},trim:function(str){return str.replace(/^\s\s*/,'').replace(/\s\s*$/,'');},camelize:function(str){var oStringList=str.split('-');var camelizedString=oStringList[0];for(var i=1,len=oStringList.length;i Date: Thu, 29 Apr 2010 00:29:49 +0100 Subject: [PATCH 03/25] Implement OSM.spam_score to return a spam score for a piece of text --- lib/osm.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/osm.rb b/lib/osm.rb index cb23b0c97..46b904477 100644 --- a/lib/osm.rb +++ b/lib/osm.rb @@ -7,6 +7,7 @@ module OSM require 'xml/libxml' require 'digest/md5' require 'RMagick' + require 'nokogiri' # The base class for API Errors. class APIError < RuntimeError @@ -498,5 +499,24 @@ module OSM return "#{tilesql} AND #{prefix}latitude BETWEEN #{minlat} AND #{maxlat} AND #{prefix}longitude BETWEEN #{minlon} AND #{maxlon}" end + # Return a spam score for a chunk of text + def self.spam_score(text) + link_count = 0 + link_size = 0 + doc = Nokogiri::HTML(text) + + if doc.content.length > 0 + doc.xpath("//a").each do |link| + link_count += 1 + link_size += link.content.length + end + + link_proportion = link_size.to_f / doc.content.length.to_f + else + link_proportion = 0 + end + + return [link_proportion - 0.2, 0.0].max * 200 + link_count * 20 + end end From 937b576bf55eae69ae8584bff049ae122ded57e5 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 30 Apr 2010 00:18:53 +0100 Subject: [PATCH 04/25] Add a spam_score method to the user model --- app/models/user.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index f02c9a5cd..a76d45710 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,6 +3,7 @@ class User < ActiveRecord::Base has_many :traces, :conditions => { :visible => true } has_many :diary_entries, :order => 'created_at DESC' + has_many :diary_comments, :order => 'created_at DESC' has_many :messages, :foreign_key => :to_user_id, :conditions => { :to_user_visible => true }, :order => 'sent_on DESC' has_many :new_messages, :class_name => "Message", :foreign_key => :to_user_id, :conditions => { :to_user_visible => true, :message_read => false }, :order => 'sent_on DESC' has_many :sent_messages, :class_name => "Message", :foreign_key => :from_user_id, :conditions => { :from_user_visible => true }, :order => 'sent_on DESC' @@ -166,4 +167,20 @@ class User < ActiveRecord::Base self.save end + ## + # return a spam score for a user + def spam_score + changeset_score = self.changesets.find(:all, :limit => 10).length * 50 + trace_score = self.traces.find(:all, :limit => 10).length * 50 + diary_entry_score = self.diary_entries.inject(0) { |s,e| s += OSM.spam_score(e.body) } + diary_comment_score = self.diary_comments.inject(0) { |s,e| s += OSM.spam_score(e.body) } + + score = 0 + score += diary_entry_score / self.diary_entries.length if self.diary_entries.length > 0 + score += diary_comment_score / self.diary_comments.length if self.diary_comments.length > 0 + score -= changeset_score + score -= trace_score + + return score + end end From 752f737497c8e5e55d4366a1250b2cb2e1464535 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 30 Apr 2010 00:21:57 +0100 Subject: [PATCH 05/25] Add a user index to diary comments --- db/migrate/050_add_user_index_to_diary_comments.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 db/migrate/050_add_user_index_to_diary_comments.rb diff --git a/db/migrate/050_add_user_index_to_diary_comments.rb b/db/migrate/050_add_user_index_to_diary_comments.rb new file mode 100644 index 000000000..e1fe0def2 --- /dev/null +++ b/db/migrate/050_add_user_index_to_diary_comments.rb @@ -0,0 +1,9 @@ +class AddUserIndexToDiaryComments < ActiveRecord::Migration + def self.up + add_index :diary_comments, [:user_id, :created_at], :name => "diary_comment_user_id_created_at_index" + end + + def self.down + remove_index :diary_comments, :name => "diary_comment_user_id_created_at_index" + end +end From 8b781bb18b406788e2d62dbef07ba1e00e371c78 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Sat, 1 May 2010 11:22:37 +0100 Subject: [PATCH 06/25] Include the user description in the spam score --- app/models/user.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index a76d45710..c6a9ad518 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -175,12 +175,12 @@ class User < ActiveRecord::Base diary_entry_score = self.diary_entries.inject(0) { |s,e| s += OSM.spam_score(e.body) } diary_comment_score = self.diary_comments.inject(0) { |s,e| s += OSM.spam_score(e.body) } - score = 0 + score = OSM.spam_score(self.description) * 2 score += diary_entry_score / self.diary_entries.length if self.diary_entries.length > 0 score += diary_comment_score / self.diary_comments.length if self.diary_comments.length > 0 score -= changeset_score score -= trace_score - return score + return score.to_i end end From 5a54630b572d222b0abea05f3e19e1b1951f0aee Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Sat, 1 May 2010 16:13:47 +0100 Subject: [PATCH 07/25] Add support for suspended and confirmed users Replace the existing "active" and "visible" with an enumerated status that allows for extra cases. Currently we have "suspended" for users who hve triggered the spam detector and "confirmed" for users that have triggered the detector but have been confirmed as vald by an admin. --- app/controllers/application_controller.rb | 2 +- app/controllers/diary_entry_controller.rb | 14 +++++----- app/controllers/user_controller.rb | 32 ++++++++++++++--------- app/models/diary_entry.rb | 2 +- app/models/user.rb | 22 +++++++++++++--- app/models/user_sweeper.rb | 2 +- app/views/user/view.html.erb | 23 ++++++++-------- config/locales/en.yml | 1 + config/routes.rb | 1 + db/migrate/051_add_status_to_user.rb | 29 ++++++++++++++++++++ 10 files changed, 90 insertions(+), 38 deletions(-) create mode 100644 db/migrate/051_add_status_to_user.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0c4117047..eebc9eb28 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,7 +8,7 @@ class ApplicationController < ActionController::Base def authorize_web if session[:user] - @user = User.find(session[:user], :conditions => {:visible => true}) + @user = User.find(session[:user], :conditions => {:status => ["active", "confirmed"]}) elsif session[:token] @user = User.authenticate(:token => session[:token]) session[:user] = @user.id diff --git a/app/controllers/diary_entry_controller.rb b/app/controllers/diary_entry_controller.rb index 6c7c9658b..52ce742bf 100644 --- a/app/controllers/diary_entry_controller.rb +++ b/app/controllers/diary_entry_controller.rb @@ -71,7 +71,7 @@ class DiaryEntryController < ApplicationController def list if params[:display_name] - @this_user = User.find_by_display_name(params[:display_name], :conditions => { :visible => true }) + @this_user = User.find_by_display_name(params[:display_name], :conditions => { :status => ["active", "confirmed"] }) if @this_user @title = t 'diary_entry.list.user_title', :user => @this_user.display_name @@ -92,7 +92,7 @@ class DiaryEntryController < ApplicationController @title = t 'diary_entry.list.in_language_title', :language => Language.find(params[:language]).english_name @entry_pages, @entries = paginate(:diary_entries, :include => :user, :conditions => { - :users => { :visible => true }, + :users => { :status => ["active", "confirmed"] }, :visible => true, :language_code => params[:language] }, @@ -102,7 +102,7 @@ class DiaryEntryController < ApplicationController @title = t 'diary_entry.list.title' @entry_pages, @entries = paginate(:diary_entries, :include => :user, :conditions => { - :users => { :visible => true }, + :users => { :status => ["active", "confirmed"] }, :visible => true }, :order => 'created_at DESC', @@ -114,7 +114,7 @@ class DiaryEntryController < ApplicationController request.format = :rss if params[:display_name] - user = User.find_by_display_name(params[:display_name], :conditions => { :visible => true }) + user = User.find_by_display_name(params[:display_name], :conditions => { :status => ["active", "confirmed"] }) if user @entries = DiaryEntry.find(:all, @@ -133,7 +133,7 @@ class DiaryEntryController < ApplicationController elsif params[:language] @entries = DiaryEntry.find(:all, :include => :user, :conditions => { - :users => { :visible => true }, + :users => { :status => ["active", "confirmed"] }, :visible => true, :language_code => params[:language] }, @@ -145,7 +145,7 @@ class DiaryEntryController < ApplicationController else @entries = DiaryEntry.find(:all, :include => :user, :conditions => { - :users => { :visible => true }, + :users => { :status => ["active", "confirmed"] }, :visible => true }, :order => 'created_at DESC', @@ -157,7 +157,7 @@ class DiaryEntryController < ApplicationController end def view - user = User.find_by_display_name(params[:display_name], :conditions => { :visible => true }) + user = User.find_by_display_name(params[:display_name], :conditions => { :status => ["active", "confirmed"] }) if user @entry = DiaryEntry.find(:first, :conditions => { diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 9551ac6d8..839c94e3a 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -11,8 +11,8 @@ class UserController < ApplicationController before_filter :require_allow_read_prefs, :only => [:api_details] before_filter :require_allow_read_gpx, :only => [:api_gpx_files] before_filter :require_cookies, :only => [:login, :confirm] - before_filter :require_administrator, :only => [:activate, :deactivate, :hide, :unhide, :delete] - before_filter :lookup_this_user, :only => [:activate, :deactivate, :hide, :unhide, :delete] + before_filter :require_administrator, :only => [:activate, :deactivate, :confirm, :hide, :unhide, :delete] + before_filter :lookup_this_user, :only => [:activate, :deactivate, :confirm, :hide, :unhide, :delete] filter_parameter_logging :password, :pass_crypt, :pass_crypt_confirmation @@ -26,7 +26,7 @@ class UserController < ApplicationController else @user = User.new(params[:user]) - @user.visible = true + @user.status = "pending" @user.data_public = true @user.description = "" if @user.description.nil? @user.creation_ip = request.remote_ip @@ -102,7 +102,7 @@ class UserController < ApplicationController @title = t 'user.lost_password.title' if params[:user] and params[:user][:email] - user = User.find_by_email(params[:user][:email], :conditions => {:visible => true}) + user = User.find_by_email(params[:user][:email], :conditions => {:status => ["pending", "active", "confirmed"]}) if user token = user.tokens.create @@ -127,7 +127,7 @@ class UserController < ApplicationController if params[:user] @user.pass_crypt = params[:user][:pass_crypt] @user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation] - @user.active = true + @user.status = "active" @user.email_valid = true if @user.save @@ -207,7 +207,7 @@ class UserController < ApplicationController token = UserToken.find_by_token(params[:confirm_string]) if token and !token.user.active? @user = token.user - @user.active = true + @user.status = "active" @user.email_valid = true @user.save! referer = token.referer @@ -232,7 +232,6 @@ class UserController < ApplicationController @user = token.user @user.email = @user.new_email @user.new_email = nil - @user.active = true @user.email_valid = true if @user.save flash[:notice] = t 'user.confirm_email.success' @@ -272,7 +271,7 @@ class UserController < ApplicationController def make_friend if params[:display_name] name = params[:display_name] - new_friend = User.find_by_display_name(name, :conditions => {:visible => true}) + new_friend = User.find_by_display_name(name, :conditions => {:status => ["active", "confirmed"]}) friend = Friend.new friend.user_id = @user.id friend.friend_user_id = new_friend.id @@ -298,7 +297,7 @@ class UserController < ApplicationController def remove_friend if params[:display_name] name = params[:display_name] - friend = User.find_by_display_name(name, :conditions => {:visible => true}) + friend = User.find_by_display_name(name, :conditions => {:status => ["active", "confirmed"]}) if @user.is_friends_with?(friend) Friend.delete_all "user_id = #{@user.id} AND friend_user_id = #{friend.id}" flash[:notice] = t 'user.remove_friend.success', :name => friend.display_name @@ -317,28 +316,35 @@ class UserController < ApplicationController ## # activate a user, allowing them to log in def activate - @this_user.update_attributes(:active => true) + @this_user.update_attributes(:status => "active") redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] end ## # deactivate a user, preventing them from logging in def deactivate - @this_user.update_attributes(:active => false) + @this_user.update_attributes(:status => "pending") + redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] + end + + ## + # confirm a user, overriding any suspension triggered by spam scoring + def confirm + @this_user.update_attributes(:status => "confirmed") redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] end ## # hide a user, marking them as logically deleted def hide - @this_user.update_attributes(:visible => false) + @this_user.update_attributes(:status => "deleted") redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] end ## # unhide a user, clearing the logically deleted flag def unhide - @this_user.update_attributes(:visible => true) + @this_user.update_attributes(:status => "active") redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] end diff --git a/app/models/diary_entry.rb b/app/models/diary_entry.rb index 0524b75cf..9146eb800 100644 --- a/app/models/diary_entry.rb +++ b/app/models/diary_entry.rb @@ -8,7 +8,7 @@ class DiaryEntry < ActiveRecord::Base has_many :visible_comments, :class_name => "DiaryComment", :include => :user, :conditions => { - :users => { :visible => true }, + :users => { :status => ["active", "confirmed" ] }, :visible => true }, :order => "diary_comments.id" diff --git a/app/models/user.rb b/app/models/user.rb index c6a9ad518..23e95bc88 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -7,7 +7,7 @@ class User < ActiveRecord::Base has_many :messages, :foreign_key => :to_user_id, :conditions => { :to_user_visible => true }, :order => 'sent_on DESC' has_many :new_messages, :class_name => "Message", :foreign_key => :to_user_id, :conditions => { :to_user_visible => true, :message_read => false }, :order => 'sent_on DESC' has_many :sent_messages, :class_name => "Message", :foreign_key => :from_user_id, :conditions => { :from_user_visible => true }, :order => 'sent_on DESC' - has_many :friends, :include => :befriendee, :conditions => ["users.visible = ?", true] + has_many :friends, :include => :befriendee, :conditions => "users.status IN ('active', 'confirmed')" has_many :tokens, :class_name => "UserToken" has_many :preferences, :class_name => "UserPreference" has_many :changesets @@ -107,7 +107,8 @@ class User < ActiveRecord::Base bounds = gc.bounds(radius) sql_for_distance = gc.sql_for_distance("home_lat", "home_lon") nearby = User.find(:all, - :conditions => ["id != ? AND visible = ? AND data_public = ? AND #{sql_for_distance} <= ?", id, true, true, radius], :order => sql_for_distance, :limit => num) + :conditions => ["id != ? AND status IN (\'active\', \'confirmed\') AND data_public = ? AND #{sql_for_distance} <= ?", id, true, radius], + :order => sql_for_distance, :limit => num) else nearby = [] end @@ -129,6 +130,18 @@ class User < ActiveRecord::Base return false end + ## + # returns true if a user is visible + def visible? + ["pending","active","confirmed"].include? self.status + end + + ## + # returns true if a user is active + def active? + ["active","confirmed"].include? self.status + end + ## # returns true if the user has the moderator role, false otherwise def moderator? @@ -154,8 +167,9 @@ class User < ActiveRecord::Base active_blocks.detect { |b| b.needs_view? } end + ## + # delete a user - leave the account but purge most personal data def delete - self.active = false self.display_name = "user_#{self.id}" self.description = "" self.home_lat = nil @@ -163,7 +177,7 @@ class User < ActiveRecord::Base self.image = nil self.email_valid = false self.new_email = nil - self.visible = false + self.status = "deleted" self.save end diff --git a/app/models/user_sweeper.rb b/app/models/user_sweeper.rb index 7f172317d..d2fd983f7 100644 --- a/app/models/user_sweeper.rb +++ b/app/models/user_sweeper.rb @@ -14,7 +14,7 @@ private def expire_cache_for(old_record, new_record) if old_record and (new_record.nil? or - old_record.visible != new_record.visible or + old_record.visible? != new_record.visible? or old_record.display_name != new_record.display_name) old_record.diary_entries.each do |entry| expire_action(:controller => 'diary_entry', :action => 'view', :display_name => old_record.display_name, :id => entry.id) diff --git a/app/views/user/view.html.erb b/app/views/user/view.html.erb index b333b5c67..07c31a1e2 100644 --- a/app/views/user/view.html.erb +++ b/app/views/user/view.html.erb @@ -59,19 +59,20 @@ <% end %> <% if @user and @user.administrator? %>
- <% if @this_user.active? %> - <%= link_to t('user.view.deactivate_user'), {:controller => 'user', :action => 'deactivate', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> - <% else %> - <%= link_to t('user.view.activate_user'), {:controller => 'user', :action => 'activate', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> + <% if ["active", "confirmed"].include? @this_user.status %> + <%= link_to t('user.view.deactivate_user'), {:controller => 'user', :action => 'deactivate', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | + <% elsif ["pending"].include? @this_user.status %> + <%= link_to t('user.view.activate_user'), {:controller => 'user', :action => 'activate', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | <% end %> - | - <% if @this_user.visible? %> - <%= link_to t('user.view.hide_user'), {:controller => 'user', :action => 'hide', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> - | - <%= link_to t('user.view.delete_user'), {:controller => 'user', :action => 'delete', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> - <% else %> - <%= link_to t('user.view.unhide_user'), {:controller => 'user', :action => 'unhide', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> + <% if ["active", "suspended"].include? @this_user.status %> + <%= link_to t('user.view.confirm_user'), {:controller => 'user', :action => 'confirm', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | <% end %> + <% if ["pending", "active", "confirmed", "suspended"].include? @this_user.status %> + <%= link_to t('user.view.hide_user'), {:controller => 'user', :action => 'hide', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | + <% else %> + <%= link_to t('user.view.unhide_user'), {:controller => 'user', :action => 'unhide', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | + <% end %> + <%= link_to t('user.view.delete_user'), {:controller => 'user', :action => 'delete', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> <% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index ba76a9b4a..ae3b0d566 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1573,6 +1573,7 @@ en: create_block: "block this user" activate_user: "activate this user" deactivate_user: "deactivate this user" + confirm_user: "confirm this user" hide_user: "hide this user" unhide_user: "unhide this user" delete_user: "delete this user" diff --git a/config/routes.rb b/config/routes.rb index 9a86f9200..9a7231041 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -160,6 +160,7 @@ ActionController::Routing::Routes.draw do |map| map.connect '/user/:display_name/account', :controller => 'user', :action => 'account' map.connect '/user/:display_name/activate', :controller => 'user', :action => 'activate' map.connect '/user/:display_name/deactivate', :controller => 'user', :action => 'deactivate' + map.connect '/user/:display_name/confirm', :controller => 'user', :action => 'confirm' map.connect '/user/:display_name/hide', :controller => 'user', :action => 'hide' map.connect '/user/:display_name/unhide', :controller => 'user', :action => 'unhide' map.connect '/user/:display_name/delete', :controller => 'user', :action => 'delete' diff --git a/db/migrate/051_add_status_to_user.rb b/db/migrate/051_add_status_to_user.rb new file mode 100644 index 000000000..cc8a2f238 --- /dev/null +++ b/db/migrate/051_add_status_to_user.rb @@ -0,0 +1,29 @@ +require 'lib/migrate' + +class AddStatusToUser < ActiveRecord::Migration + def self.up + create_enumeration :user_status_enum, ["pending","active","confirmed","suspended","deleted"] + + add_column :users, :status, :user_status_enum, :null => false, :default => "pending" + + User.update_all("status = 'deleted'", { :visible => false }) + User.update_all("status = 'pending'", { :visible => true, :active => 0 }) + User.update_all("status = 'active'", { :visible => true, :active => 1 }) + + remove_column :users, :active + remove_column :users, :visible + end + + def self.down + add_column :users, :visible, :boolean, :default => true, :null => false + add_column :users, :active, :integer, :default => 0, :null => false + + User.update_all("visible = true, active = 1", { :status => "active" }) + User.update_all("visible = true, active = 0", { :status => "pending" }) + User.update_all("visible = false, active = 1", { :status => "deleted" }) + + remove_column :users, :status + + drop_enumeration :user_status_enum + end +end From 980c2fa30197eca1a609342a75eb66b7068269d1 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Sat, 1 May 2010 17:03:18 +0100 Subject: [PATCH 08/25] Suspend users if their spam score gets too high Use an observer to watch all diary and user updates and, if the user is not confirmed, chek their spam score and suspend then if it has got too high. --- app/models/spam_observer.rb | 15 +++++++++++++++ config/application.yml | 2 ++ config/environment.rb | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 app/models/spam_observer.rb diff --git a/app/models/spam_observer.rb b/app/models/spam_observer.rb new file mode 100644 index 000000000..21561f671 --- /dev/null +++ b/app/models/spam_observer.rb @@ -0,0 +1,15 @@ +class SpamObserver < ActiveRecord::Observer + observe User, DiaryEntry, DiaryComment + + def after_save(record) + case + when record.is_a?(User): user = record + when record.is_a?(DiaryEntry): user = record.user + when record.is_a?(DiaryComment): user = record.user + end + + if user.status == "active" and user.spam_score > APP_CONFIG['spam_threshold'] + user.update_attributes(:status => "suspended") + end + end +end diff --git a/config/application.yml b/config/application.yml index 363cc6398..c0622df75 100644 --- a/config/application.yml +++ b/config/application.yml @@ -22,6 +22,8 @@ standard_settings: &standard_settings # Quova authentication details #quova_username: "" #quova_password: "" + # Spam threshold + spam_theshold: 50 development: <<: *standard_settings diff --git a/config/environment.rb b/config/environment.rb index 018e97451..d8f9b2fc8 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -100,7 +100,7 @@ Rails::Initializer.run do |config| config.active_record.schema_format = :sql # Activate observers that should always be running - # config.active_record.observers = :cacher, :garbage_collector + config.active_record.observers = :spam_observer # Make Active Record use UTC-base instead of local time config.active_record.default_timezone = :utc From 200a1ab5c7b26c4e59630f5f48c3d08320376ebc Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Sat, 1 May 2010 17:30:37 +0100 Subject: [PATCH 09/25] Show administrators the status and spam score for a user --- app/views/user/view.html.erb | 2 ++ config/locales/en.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/views/user/view.html.erb b/app/views/user/view.html.erb index 07c31a1e2..b5890fca2 100644 --- a/app/views/user/view.html.erb +++ b/app/views/user/view.html.erb @@ -81,6 +81,8 @@ <% if @user and @user.administrator? %>

<%= t 'user.view.email address' %> <%= @this_user.email %>

<%= t 'user.view.created from' %> <%= @this_user.creation_ip %>

+

<%= t 'user.view.status' %> <%= @this_user.status.capitalize %>

+

<%= t 'user.view.spam score' %> <%= @this_user.spam_score %>

<% end %>

<%= t 'user.view.description' %>

diff --git a/config/locales/en.yml b/config/locales/en.yml index ae3b0d566..3c5073e21 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1549,6 +1549,8 @@ en: ago: "({{time_in_words_ago}} ago)" email address: "Email address:" created from: "Created from:" + status: "Status:" + spam score: "Spam Score:" description: Description user location: User location if set location: "If you set your location, a pretty map and stuff will appear here. You can set your home location on your {{settings_link}} page." From 552a647810d16013b26a93299406d5797157faba Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Sat, 1 May 2010 18:28:41 +0100 Subject: [PATCH 10/25] Merge all the user status changing methods into one --- app/controllers/user_controller.rb | 40 +++++------------------------- app/views/user/view.html.erb | 10 ++++---- config/routes.rb | 6 +---- 3 files changed, 12 insertions(+), 44 deletions(-) diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 839c94e3a..f24e1ee72 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -11,12 +11,12 @@ class UserController < ApplicationController before_filter :require_allow_read_prefs, :only => [:api_details] before_filter :require_allow_read_gpx, :only => [:api_gpx_files] before_filter :require_cookies, :only => [:login, :confirm] - before_filter :require_administrator, :only => [:activate, :deactivate, :confirm, :hide, :unhide, :delete] - before_filter :lookup_this_user, :only => [:activate, :deactivate, :confirm, :hide, :unhide, :delete] + before_filter :require_administrator, :only => [:set_status, :delete] + before_filter :lookup_this_user, :only => [:set_status, :delete] filter_parameter_logging :password, :pass_crypt, :pass_crypt_confirmation - cache_sweeper :user_sweeper, :only => [:account, :hide, :unhide, :delete] + cache_sweeper :user_sweeper, :only => [:account, :set_status, :delete] def save @title = t 'user.new.title' @@ -314,37 +314,9 @@ class UserController < ApplicationController end ## - # activate a user, allowing them to log in - def activate - @this_user.update_attributes(:status => "active") - redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] - end - - ## - # deactivate a user, preventing them from logging in - def deactivate - @this_user.update_attributes(:status => "pending") - redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] - end - - ## - # confirm a user, overriding any suspension triggered by spam scoring - def confirm - @this_user.update_attributes(:status => "confirmed") - redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] - end - - ## - # hide a user, marking them as logically deleted - def hide - @this_user.update_attributes(:status => "deleted") - redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] - end - - ## - # unhide a user, clearing the logically deleted flag - def unhide - @this_user.update_attributes(:status => "active") + # sets a user's status + def set_status + @this_user.update_attributes(:status => params[:status]) redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] end diff --git a/app/views/user/view.html.erb b/app/views/user/view.html.erb index b5890fca2..2aca75f53 100644 --- a/app/views/user/view.html.erb +++ b/app/views/user/view.html.erb @@ -60,17 +60,17 @@ <% if @user and @user.administrator? %>
<% if ["active", "confirmed"].include? @this_user.status %> - <%= link_to t('user.view.deactivate_user'), {:controller => 'user', :action => 'deactivate', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | + <%= link_to t('user.view.deactivate_user'), {:controller => 'user', :action => 'set_status', :status => 'pending', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | <% elsif ["pending"].include? @this_user.status %> - <%= link_to t('user.view.activate_user'), {:controller => 'user', :action => 'activate', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | + <%= link_to t('user.view.activate_user'), {:controller => 'user', :action => 'set_status', :status => 'active', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | <% end %> <% if ["active", "suspended"].include? @this_user.status %> - <%= link_to t('user.view.confirm_user'), {:controller => 'user', :action => 'confirm', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | + <%= link_to t('user.view.confirm_user'), {:controller => 'user', :action => 'set_status', :status => 'confirmed', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | <% end %> <% if ["pending", "active", "confirmed", "suspended"].include? @this_user.status %> - <%= link_to t('user.view.hide_user'), {:controller => 'user', :action => 'hide', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | + <%= link_to t('user.view.hide_user'), {:controller => 'user', :action => 'set_status', :status => 'deleted', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | <% else %> - <%= link_to t('user.view.unhide_user'), {:controller => 'user', :action => 'unhide', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | + <%= link_to t('user.view.unhide_user'), {:controller => 'user', :action => 'set_status', :status => 'active', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> | <% end %> <%= link_to t('user.view.delete_user'), {:controller => 'user', :action => 'delete', :display_name => @this_user.display_name}, {:confirm => t('user.view.confirm')} %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index 9a7231041..82f4e3a9f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -158,11 +158,7 @@ ActionController::Routing::Routes.draw do |map| map.connect '/user/:display_name/diary/:id/hide', :controller => 'diary_entry', :action => 'hide', :id => /\d+/ map.connect '/user/:display_name/diary/:id/hidecomment/:comment', :controller => 'diary_entry', :action => 'hidecomment', :id => /\d+/, :comment => /\d+/ map.connect '/user/:display_name/account', :controller => 'user', :action => 'account' - map.connect '/user/:display_name/activate', :controller => 'user', :action => 'activate' - map.connect '/user/:display_name/deactivate', :controller => 'user', :action => 'deactivate' - map.connect '/user/:display_name/confirm', :controller => 'user', :action => 'confirm' - map.connect '/user/:display_name/hide', :controller => 'user', :action => 'hide' - map.connect '/user/:display_name/unhide', :controller => 'user', :action => 'unhide' + map.connect '/user/:display_name/set_status', :controller => 'user', :action => 'set_status' map.connect '/user/:display_name/delete', :controller => 'user', :action => 'delete' map.connect '/diary/new', :controller => 'diary_entry', :action => 'new' map.connect '/diary', :controller => 'diary_entry', :action => 'list' From 5d3992daca978f714ff9d6758b6155b9f08ee3f5 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Mon, 3 May 2010 17:09:37 +0100 Subject: [PATCH 11/25] Tell users their account has been suspended when they try and login --- app/controllers/user_controller.rb | 4 +++- app/models/user.rb | 7 +++++-- config/locales/en.yml | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index f24e1ee72..af0ccba05 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -173,8 +173,10 @@ class UserController < ApplicationController else redirect_to :controller => 'site', :action => 'index' end - elsif User.authenticate(:username => email_or_display_name, :password => pass, :inactive => true) + elsif User.authenticate(:username => email_or_display_name, :password => pass, :pending => true) flash.now[:error] = t 'user.login.account not active' + elsif User.authenticate(:username => email_or_display_name, :password => pass, :suspended => true) + flash.now[:error] = t 'user.login.account suspended' else flash.now[:error] = t 'user.login.auth failure' end diff --git a/app/models/user.rb b/app/models/user.rb index 23e95bc88..31b0f27a0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -56,8 +56,11 @@ class User < ActiveRecord::Base user = token.user if token end - if user - user = nil unless user.visible? and (user.active? or options[:inactive]) + if user and + ( user.status == "deleted" or + ( user.status == "pending" and not options[:pending] ) or + ( user.status == "suspended" and not options[:suspended] ) ) + user = nil end token.update_attribute(:expiry, 1.week.from_now) if token and user diff --git a/config/locales/en.yml b/config/locales/en.yml index 3c5073e21..21e5795cb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1489,6 +1489,7 @@ en: lost password link: "Lost your password?" login_button: "Login" account not active: "Sorry, your account is not active yet.
Please click on the link in the account confirmation email to activate your account." + account suspended: Sorry, your account has been suspended due to suspicious activity.
Please contact the webmaster if you wish to discuss this. auth failure: "Sorry, could not log in with those details." logout: title: "Logout" From ae8c0b3baff821423ef4830abab075ffb8f4ead9 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Tue, 4 May 2010 14:44:28 +0100 Subject: [PATCH 12/25] Add a user list view for administrators --- app/controllers/user_controller.rb | 35 +++++++++++++++++++++++--- app/views/user/_user.html.erb | 20 +++++++++++++++ app/views/user/list.html.erb | 40 ++++++++++++++++++++++++++++++ config/locales/en.yml | 10 ++++++++ config/routes.rb | 5 +++- public/stylesheets/common.css | 21 ++++++++++++++++ 6 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 app/views/user/_user.html.erb create mode 100644 app/views/user/list.html.erb diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index af0ccba05..e5db74f38 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -11,7 +11,7 @@ class UserController < ApplicationController before_filter :require_allow_read_prefs, :only => [:api_details] before_filter :require_allow_read_gpx, :only => [:api_gpx_files] before_filter :require_cookies, :only => [:login, :confirm] - before_filter :require_administrator, :only => [:set_status, :delete] + before_filter :require_administrator, :only => [:set_status, :delete, :list] before_filter :lookup_this_user, :only => [:set_status, :delete] filter_parameter_logging :password, :pass_crypt, :pass_crypt_confirmation @@ -328,14 +328,43 @@ class UserController < ApplicationController @this_user.delete redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] end + + ## + # display a list of users matching specified criteria + def list + if request.post? + ids = params[:user].keys.collect { |id| id.to_i } + + User.update_all("status = 'confirmed'", :id => ids) if params[:confirm] + User.update_all("status = 'deleted'", :id => ids) if params[:hide] + end + + conditions = Hash.new + conditions[:status] = params[:status] if params[:status] + conditions[:creation_ip] = params[:ip] if params[:ip] + + @user_pages, @users = paginate(:users, + :conditions => conditions, + :order => :id, + :per_page => 50) + end + private + ## # require that the user is a administrator, or fill out a helpful error message # and return them to the user page. def require_administrator - unless @user.administrator? + if @user and not @user.administrator? flash[:error] = t('user.filter.not_an_administrator') - redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] + + if params[:display_name] + redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] + else + redirect_to :controller => 'user', :action => 'login', :referer => request.request_uri + end + elsif not @user + redirect_to :controller => 'user', :action => 'login', :referer => request.request_uri end end diff --git a/app/views/user/_user.html.erb b/app/views/user/_user.html.erb new file mode 100644 index 000000000..66f6cd3bc --- /dev/null +++ b/app/views/user/_user.html.erb @@ -0,0 +1,20 @@ +<% cl = cycle('table0', 'table1') %> + + + + <%= user_thumbnail(user) %> + + +

+ <%= t 'user.list.summary', + :name => h(user.display_name), + :ip_address => link_to(user.creation_ip, :ip => user.creation_ip), + :date => l(user.creation_time, :format => :friendly) + %> +

+ <%= htmlize(user.description) %> + + + <%= check_box_tag "user_#{user.id}", "", false, :name => "user[#{user.id}]" %> + + diff --git a/app/views/user/list.html.erb b/app/views/user/list.html.erb new file mode 100644 index 000000000..6f010e267 --- /dev/null +++ b/app/views/user/list.html.erb @@ -0,0 +1,40 @@ +<% @title = t('user.list.title') %> + +

<%= t('user.list.heading') %>

+ +<% unless @users.empty? %> + <% form_tag :status => params[:status], :ip => params[:ip] do %> + + + + + + <%= render :partial => 'user', :collection => @users %> +
+ <%= t 'user.list.showing', + :page => @user_pages.current_page.number, + :first_item => @user_pages.current_page.first_item, + :last_item => @user_pages.current_page.last_item, + :count => @user_pages.current_page.last_item - @user_pages.current_page.first_item + 1 + %> + <% if @user_pages.page_count > 1 %> + | <%= pagination_links_each(@user_pages, {}) { |n| link_to n, :page => n } %> + <% end %> + + <%= + check_box_tag("user_all", "1", false, :onchange => update_page do |page| + @users.each do |user| + page << "$('user_#{user.id}').checked = $('user_all').checked;" + end + end) + %> +
+ +
+ <%= submit_tag t('user.list.confirm'), :name => "confirm" %> + <%= submit_tag t('user.list.hide'), :name => "hide" %> +
+ <% end %> +<% else %> +

<%= t "user.list.empty" %>

+<% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 21e5795cb..e521299e7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1644,6 +1644,16 @@ en: not_a_friend: "{{name}} is not one of your friends." filter: not_an_administrator: "You need to be an administrator to perform that action." + list: + title: Users + heading: Users + showing: + one: Showing page {{page}} ({{first_item}} of {{count}}) + other: Showing page {{page}} ({{first_item}}-{{last_item}} of {{count}}) + summary: "{{name}} created from {{ip_address}} on {{date}}" + confirm: Confirm Selected Users + hide: Hide Selected Users + empty: No matching users found user_role: filter: not_an_administrator: "Only administrators can perform user role management, and you are not an administrator." diff --git a/config/routes.rb b/config/routes.rb index 82f4e3a9f..b15d77e31 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -166,7 +166,10 @@ ActionController::Routing::Routes.draw do |map| map.connect '/diary/:language', :controller => 'diary_entry', :action => 'list' map.connect '/diary/:language/rss', :controller => 'diary_entry', :action => 'rss' - + # user lists + map.connect '/users', :controller => 'user', :action => 'list' + map.connect '/users/:status', :controller => 'user', :action => 'list' + # test pages map.connect '/test/populate/:table/:from/:count', :controller => 'test', :action => 'populate' map.connect '/test/populate/:table/:count', :controller => 'test', :action => 'populate', :from => 1 diff --git a/public/stylesheets/common.css b/public/stylesheets/common.css index b6ee99712..73f0fb788 100644 --- a/public/stylesheets/common.css +++ b/public/stylesheets/common.css @@ -562,6 +562,27 @@ hr { color: gray; } +/* Rules for the user list */ + +#user_list { + width: 100%; + font-size: small; +} + +#user_list tr { + vertical-align: center; +} + +#user_list p { + margin-top: 0px; + margin-bottom: 0px; +} + +#user_list_actions { + float: right; + margin-top: 10px; +} + /* Rules for the account settings page */ #accountForm td { From 97c2406ae4abfc56ce9ebd1d31480d92f3c40c7b Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Thu, 6 May 2010 21:52:27 +0100 Subject: [PATCH 13/25] Fix user visibility check --- app/controllers/changeset_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/changeset_controller.rb b/app/controllers/changeset_controller.rb index 79000c685..d0a357c85 100644 --- a/app/controllers/changeset_controller.rb +++ b/app/controllers/changeset_controller.rb @@ -255,7 +255,7 @@ class ChangesetController < ApplicationController conditions = conditions_nonempty if params[:display_name] - user = User.find_by_display_name(params[:display_name], :conditions => { :visible => true }) + user = User.find_by_display_name(params[:display_name], :conditions => { :status => ["active", "confirmed"] }) if user if user.data_public? or user == @user From 674123e055c4741c1e1ceabd0b74dff8d46f1adc Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Thu, 6 May 2010 22:01:45 +0100 Subject: [PATCH 14/25] Fix typo --- config/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/application.yml b/config/application.yml index c0622df75..a1fbd887a 100644 --- a/config/application.yml +++ b/config/application.yml @@ -23,7 +23,7 @@ standard_settings: &standard_settings #quova_username: "" #quova_password: "" # Spam threshold - spam_theshold: 50 + spam_threshold: 50 development: <<: *standard_settings From 3026da0cb028a559649282f0498a7cbac1fb633b Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Thu, 6 May 2010 22:11:38 +0100 Subject: [PATCH 15/25] Fix user visibility check --- app/controllers/trace_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/trace_controller.rb b/app/controllers/trace_controller.rb index 3c16b9a80..f8ce29aba 100644 --- a/app/controllers/trace_controller.rb +++ b/app/controllers/trace_controller.rb @@ -27,7 +27,7 @@ class TraceController < ApplicationController # from display name, pick up user id if one user's traces only display_name = params[:display_name] if target_user.nil? and !display_name.blank? - target_user = User.find(:first, :conditions => [ "visible = ? and display_name = ?", true, display_name]) + target_user = User.find(:first, :conditions => { :status => ["active", "confirmed"], :display_name => display_name }) if target_user.nil? @title = t'trace.no_such_user.title' @not_found_user = display_name From 20cc601f854d69596df6fe0ec9c6b957eb9dda6d Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Thu, 6 May 2010 22:11:55 +0100 Subject: [PATCH 16/25] Fix tests for changes to user model --- test/fixtures/users.yml | 12 ++++++------ test/unit/user_test.rb | 5 +++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 1849fd4d9..eb3c6ef6d 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -2,7 +2,7 @@ normal_user: id: 1 email: test@openstreetmap.org - active: true + status: active pass_crypt: <%= Digest::MD5.hexdigest('test') %> creation_time: "2007-01-01 00:00:00" display_name: test @@ -15,7 +15,7 @@ normal_user: public_user: id: 2 email: test@example.com - active: true + status: active pass_crypt: <%= Digest::MD5.hexdigest('test') %> creation_time: "2008-05-01 01:23:45" display_name: test2 @@ -28,7 +28,7 @@ public_user: inactive_user: id: 3 email: inactive@openstreetmap.org - active: false + status: pending pass_crypt: <%= Digest::MD5::hexdigest('test2') %> creation_time: "2008-07-01 02:23:45" display_name: Inactive User @@ -41,7 +41,7 @@ inactive_user: second_public_user: id: 4 email: public@OpenStreetMap.org - active: true + status: active pass_crypt: <%= Digest::MD5.hexdigest('test') %> creation_time: "2008-05-01 01:23:45" display_name: pulibc_test2 @@ -54,7 +54,7 @@ second_public_user: moderator_user: id: 5 email: moderator@example.com - active: true + status: active pass_crypt: <%= Digest::MD5.hexdigest('test') %> creation_time: "2008-05-01 01:23:45" display_name: moderator @@ -63,7 +63,7 @@ moderator_user: administrator_user: id: 6 email: administrator@example.com - active: true + status: active pass_crypt: <%= Digest::MD5.hexdigest('test') %> creation_time: "2008-05-01 01:23:45" display_name: administrator diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index f1994f4dd..ac2bd5e71 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../test_helper' class UserTest < ActiveSupport::TestCase @@ -18,7 +19,7 @@ class UserTest < ActiveSupport::TestCase def test_unique_email new_user = User.new(:email => users(:normal_user).email, - :active => 1, + :status => "active", :pass_crypt => Digest::MD5.hexdigest('test'), :display_name => "new user", :data_public => 1, @@ -29,7 +30,7 @@ class UserTest < ActiveSupport::TestCase def test_unique_display_name new_user = User.new(:email => "tester@openstreetmap.org", - :active => 0, + :status => "pending", :pass_crypt => Digest::MD5.hexdigest('test'), :display_name => users(:normal_user).display_name, :data_public => 1, From fc7488f28ad9861f9c9041bbb184e3c082be348c Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 7 May 2010 09:03:12 +0100 Subject: [PATCH 17/25] Link the username in the user list to their profile --- app/views/user/_user.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/user/_user.html.erb b/app/views/user/_user.html.erb index 66f6cd3bc..2779f8762 100644 --- a/app/views/user/_user.html.erb +++ b/app/views/user/_user.html.erb @@ -7,7 +7,7 @@

<%= t 'user.list.summary', - :name => h(user.display_name), + :name => link_to(h(user.display_name), :action => "view", :display_name => user.display_name), :ip_address => link_to(user.creation_ip, :ip => user.creation_ip), :date => l(user.creation_time, :format => :friendly) %> From b9deb68de1a9025cf36ed617655a4ce7c38ed47f Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 7 May 2010 09:05:55 +0100 Subject: [PATCH 18/25] Display total user count correctly in user list --- app/views/user/list.html.erb | 1 + config/locales/en.yml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/user/list.html.erb b/app/views/user/list.html.erb index 6f010e267..c91ce71e6 100644 --- a/app/views/user/list.html.erb +++ b/app/views/user/list.html.erb @@ -11,6 +11,7 @@ :page => @user_pages.current_page.number, :first_item => @user_pages.current_page.first_item, :last_item => @user_pages.current_page.last_item, + :items => @user_pages.item_count, :count => @user_pages.current_page.last_item - @user_pages.current_page.first_item + 1 %> <% if @user_pages.page_count > 1 %> diff --git a/config/locales/en.yml b/config/locales/en.yml index e521299e7..b7513a0f2 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1648,8 +1648,8 @@ en: title: Users heading: Users showing: - one: Showing page {{page}} ({{first_item}} of {{count}}) - other: Showing page {{page}} ({{first_item}}-{{last_item}} of {{count}}) + one: Showing page {{page}} ({{first_item}} of {{items}}) + other: Showing page {{page}} ({{first_item}}-{{last_item}} of {{items}}) summary: "{{name}} created from {{ip_address}} on {{date}}" confirm: Confirm Selected Users hide: Hide Selected Users From 72118727904ca4b34ea8f63c40f2701782d93284 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 7 May 2010 09:29:38 +0100 Subject: [PATCH 19/25] Don't try and display IP address for users without one --- app/views/user/_user.html.erb | 17 ++++++++++++----- config/locales/en.yml | 1 + 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/views/user/_user.html.erb b/app/views/user/_user.html.erb index 2779f8762..bbc89f965 100644 --- a/app/views/user/_user.html.erb +++ b/app/views/user/_user.html.erb @@ -6,11 +6,18 @@

- <%= t 'user.list.summary', - :name => link_to(h(user.display_name), :action => "view", :display_name => user.display_name), - :ip_address => link_to(user.creation_ip, :ip => user.creation_ip), - :date => l(user.creation_time, :format => :friendly) - %> + <% if user.creation_ip %> + <%= t 'user.list.summary', + :name => link_to(h(user.display_name), :action => "view", :display_name => user.display_name), + :ip_address => link_to(user.creation_ip, :ip => user.creation_ip), + :date => l(user.creation_time, :format => :friendly) + %> + <% else %> + <%= t 'user.list.summary_no_ip', + :name => link_to(h(user.display_name), :action => "view", :display_name => user.display_name), + :date => l(user.creation_time, :format => :friendly) + %> + <% end %>

<%= htmlize(user.description) %> diff --git a/config/locales/en.yml b/config/locales/en.yml index b7513a0f2..9775416e4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1651,6 +1651,7 @@ en: one: Showing page {{page}} ({{first_item}} of {{items}}) other: Showing page {{page}} ({{first_item}}-{{last_item}} of {{items}}) summary: "{{name}} created from {{ip_address}} on {{date}}" + summary_no_ip: "{{name}} created on {{date}}" confirm: Confirm Selected Users hide: Hide Selected Users empty: No matching users found From 9230721a1f3091ec47d5751c6b5aaead599df49f Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 7 May 2010 10:00:24 +0100 Subject: [PATCH 20/25] Redirect suspended users to an information page If the current session is for a logged in user and that user has been suspended then log them out and redirect them to a page explaining that their account has been suspended. --- app/controllers/application_controller.rb | 9 ++++++++- app/views/user/suspended.html.erb | 5 +++++ config/locales/en.yml | 13 +++++++++++++ config/routes.rb | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 app/views/user/suspended.html.erb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index eebc9eb28..a53fb5374 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,7 +8,14 @@ class ApplicationController < ActionController::Base def authorize_web if session[:user] - @user = User.find(session[:user], :conditions => {:status => ["active", "confirmed"]}) + @user = User.find(session[:user], :conditions => {:status => ["active", "confirmed", "suspended"]}) + + if @user.status == "suspended" + session[:user] = nil + session_expires_automatically + + redirect_to :controller => "user", :action => "suspended" + end elsif session[:token] @user = User.authenticate(:token => session[:token]) session[:user] = @user.id diff --git a/app/views/user/suspended.html.erb b/app/views/user/suspended.html.erb new file mode 100644 index 000000000..27b8dc3f5 --- /dev/null +++ b/app/views/user/suspended.html.erb @@ -0,0 +1,5 @@ +<% @title = t "user.suspended.title" %> + +

<%= t "user.suspended.heading" %>

+ +<%= t "user.suspended.body", :webmaster => "webmaster@openstreetmap.org" %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 9775416e4..fbf8e7a04 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1655,6 +1655,19 @@ en: confirm: Confirm Selected Users hide: Hide Selected Users empty: No matching users found + suspended: + title: Account Suspended + heading: Account Suspended + body: | +

+ Sorry, your account has been automatically suspended due to + suspicious activity. +

+

+ This decision will be reviewed by an administrator shortly, or + you may contact the webmaster if + you wish to discuss this. +

user_role: filter: not_an_administrator: "Only administrators can perform user role management, and you are not an administrator." diff --git a/config/routes.rb b/config/routes.rb index b15d77e31..7e27ee19e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -104,6 +104,7 @@ ActionController::Routing::Routes.draw do |map| map.connect '/user/go_public', :controller => 'user', :action => 'go_public' map.connect '/user/reset-password', :controller => 'user', :action => 'reset_password' map.connect '/user/forgot-password', :controller => 'user', :action => 'lost_password' + map.connect '/user/suspended', :controller => 'user', :action => 'suspended' map.connect '/index.html', :controller => 'site', :action => 'index' map.connect '/edit.html', :controller => 'site', :action => 'edit' From 7774237a11f1f6b78e0b75a3c1d6a499f9feef45 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 7 May 2010 10:01:24 +0100 Subject: [PATCH 21/25] Redirect back to settings after updating user settings When we've saved a user's settings, redirect back to their settings page instead of just rerendering so that a suspended user check will be done. --- app/controllers/user_controller.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index e5db74f38..5b9f5a0c7 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -70,9 +70,9 @@ class UserController < ApplicationController set_locale if @user.new_email.nil? or @user.new_email.empty? - flash.now[:notice] = t 'user.account.flash update success' + flash[:notice] = t 'user.account.flash update success' else - flash.now[:notice] = t 'user.account.flash update success confirm needed' + flash[:notice] = t 'user.account.flash update success confirm needed' begin Notifier.deliver_email_confirm(@user, @user.tokens.create) @@ -80,6 +80,8 @@ class UserController < ApplicationController # Ignore errors sending email end end + + redirect_to :action => "account", :display_name => @user.display_name end else if flash[:errors] From 68bb9b3b812a929ac7b281e4a49d772b6de747a7 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 7 May 2010 11:09:54 +0100 Subject: [PATCH 22/25] Fix statistics script to reflect changes to user model --- script/statistics | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/statistics b/script/statistics index 2e60d630f..4ceb92cfc 100755 --- a/script/statistics +++ b/script/statistics @@ -16,7 +16,7 @@ puts "

OpenStreetMap stats report run at #{start_time.to_s}

" begin ActiveRecord::Base.transaction do - user_count = User.count(:conditions => "active = 1") + user_count = User.count(:conditions => { :status => ["active", "confirmed", "suspended"] }) tracepoint_count = Tracepoint.count() node_count = Node.count(:conditions => "visible = true") way_count = Way.count(:conditions => "visible = true") From c86e52dee95af2100bda6a0eca7572009ab3788a Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 7 May 2010 14:07:39 +0100 Subject: [PATCH 23/25] Preserve the page number when submitting the form --- app/views/user/list.html.erb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/views/user/list.html.erb b/app/views/user/list.html.erb index c91ce71e6..02378b451 100644 --- a/app/views/user/list.html.erb +++ b/app/views/user/list.html.erb @@ -3,7 +3,10 @@

<%= t('user.list.heading') %>

<% unless @users.empty? %> - <% form_tag :status => params[:status], :ip => params[:ip] do %> + <% form_tag do %> + <%= hidden_field_tag :status, params[:status] if params[:status] %> + <%= hidden_field_tag :ip, params[:ip] if params[:ip] %> + <%= hidden_field_tag :page, params[:page] if params[:page] %>
From d50cf2b102793e8da000b580d5e4a55fc2248854 Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 7 May 2010 14:08:07 +0100 Subject: [PATCH 24/25] Preserve parameters in pagination links --- app/views/user/list.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/user/list.html.erb b/app/views/user/list.html.erb index 02378b451..fac7c442f 100644 --- a/app/views/user/list.html.erb +++ b/app/views/user/list.html.erb @@ -18,7 +18,7 @@ :count => @user_pages.current_page.last_item - @user_pages.current_page.first_item + 1 %> <% if @user_pages.page_count > 1 %> - | <%= pagination_links_each(@user_pages, {}) { |n| link_to n, :page => n } %> + | <%= pagination_links_each(@user_pages, {}) { |n| link_to n, params.merge(:page => n) } %> <% end %> From 1eba0609296c8208fd69062a189371c05ebce11e Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Fri, 7 May 2010 14:08:25 +0100 Subject: [PATCH 25/25] Redirect after processing user changes After we have processed the requested user changes, redirect back to the list so that the resulting page is reloadable without getting resubmission warnings from the browser. --- app/controllers/user_controller.rb | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 5b9f5a0c7..222840a06 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -339,16 +339,18 @@ class UserController < ApplicationController User.update_all("status = 'confirmed'", :id => ids) if params[:confirm] User.update_all("status = 'deleted'", :id => ids) if params[:hide] + + redirect_to url_for(:status => params[:status], :ip => params[:ip], :page => params[:page]) + else + conditions = Hash.new + conditions[:status] = params[:status] if params[:status] + conditions[:creation_ip] = params[:ip] if params[:ip] + + @user_pages, @users = paginate(:users, + :conditions => conditions, + :order => :id, + :per_page => 50) end - - conditions = Hash.new - conditions[:status] = params[:status] if params[:status] - conditions[:creation_ip] = params[:ip] if params[:ip] - - @user_pages, @users = paginate(:users, - :conditions => conditions, - :order => :id, - :per_page => 50) end private