Initial import from Docker volume

This commit is contained in:
root
2025-12-26 13:11:43 +00:00
commit 4998dc066a
13336 changed files with 1767801 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.pool import Pool
from . import res
def register():
Pool.register(
res.User,
res.UserLoginSMSCode,
module='authentication_sms', type_='model')

Binary file not shown.

View File

@@ -0,0 +1,38 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
#, fuzzy
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Мобилен"
#, fuzzy
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Код"
#, fuzzy
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Потребител"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Mòbil"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Codi"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Usuari"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ID"
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Número de telèfon que suporta rebre SMS."
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s codi %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr "Codi SMS per %(login)s"
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "Codi SMS"

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr ""
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr ""
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr ""
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Mobiltelefon"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Code"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Benutzer"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "Benutzer ID"
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Eine Telefonnummer, die den Empfang von SMS unterstützt."
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s Code %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr "SMS Code für %(login)s"
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "SMS Code"

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Móvil"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Código"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Usuario"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ID usuario"
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Número de teléfono que puede recibir SMS."
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s código %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr "Código SMS para %(login)s"
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "Código SMS"

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr ""
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr ""
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr ""
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,36 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Mobiil"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Kood"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Kasutaja"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "Kasutaja ID"
#, fuzzy
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Telefoninumber mis toetab SMSi vastuvõtmist"
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(nimi) kood %(kood)id"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "SMS kood"

View File

@@ -0,0 +1,36 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "موبایل"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "کد"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "کاربر"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "شناسه کاربر"
#, fuzzy
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "شماره تلفن همراه که پیام کوتاه را پشتیبانی کند"
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "\"%(name)s\" کد \"%(کد)s\""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "کد پیامک"

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr ""
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr ""
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr ""
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Mobile"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Code"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Utilisateur"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ID d'utilisateur"
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Numéro de téléphone qui support la réception de SMS."
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s code %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr "Code SMS pour %(login)s"
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "Code SMS"

View File

@@ -0,0 +1,38 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
#, fuzzy
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Mobiltelefon"
#, fuzzy
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Partner kód"
#, fuzzy
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Felhasználó"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Mobile"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Kode"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Pengguna"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ID Pengguna"
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Nomor telepon yang mendukung penerimaan SMS."
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s kode %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr "Kode SMS untuk %(login)s"
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "Kode SMS"

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Cellulare"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Codice"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Utente"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ID utente"
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Numero telefonico abilitato alla ricezione di SMS."
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s codice %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr "Codice SMS per %(login)s"
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "codice SMS"

View File

@@ -0,0 +1,37 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "ໂທລະສັບມືຖື"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "ລະຫັດ"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "ຜູ້ໃຊ້"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ລະຫັດຜູ້ໃຊ້"
#, fuzzy
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "ເລກໂທລະສັບ ທີ່ຮອງຮັບ ການຮັບຂໍ້ຄວາມສັ້ນ"
#, fuzzy
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s ລະຫັດ %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "ລະຫັດຂໍ້ຄວາມສັ້ນ"

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr ""
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr ""
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr ""
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Mobiel"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Code"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Gebruiker"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "Gebruiker ID"
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Telefoonnummer dat het ontvangen van smssen ondersteunt."
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s code %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr "SMS-code voor%(login)s"
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "SMS-code"

View File

@@ -0,0 +1,37 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Komórka"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Kod"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Użytkownik"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ID użytkownika"
#, fuzzy
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Numer telefonu, który umożliwia otrzymywanie SMS-ów"
#, fuzzy
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s kod %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "Kod SMS"

View File

@@ -0,0 +1,36 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Celular"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Código"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Usuário"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ID do Usuário"
#, fuzzy
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Número de telefone que pode receber SMS"
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s código %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "Código SMS"

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Mobil"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Cod"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Utilizator"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ID-ul de utilizator"
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Număr de telefon care acceptă primirea de SMS-uri."
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr "Cod SMS pentru %(login)s"
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "Cod SMS"

View File

@@ -0,0 +1,38 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
#, fuzzy
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "сот.телефон"
#, fuzzy
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Код языка"
#, fuzzy
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Пользователь"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr "Mobilni"
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "Šifra"
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "Uporabnik"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr "ID uporabnika"
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr "Telefonska številka, ki omogoča prejem SMS."
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr "%(name)s šifra %(code)s"
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr "SMS koda za %(login)s"
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr "SMS šifra"

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr ""
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr ""
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr ""
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,35 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr ""
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr ""
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr ""
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,37 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:res.user,mobile:"
msgid "Mobile"
msgstr ""
#, fuzzy
msgctxt "field:res.user.login.sms_code,code:"
msgid "Code"
msgstr "语言编码"
#, fuzzy
msgctxt "field:res.user.login.sms_code,user:"
msgid "User"
msgstr "用户"
msgctxt "field:res.user.login.sms_code,user_id:"
msgid "User ID"
msgstr ""
msgctxt "help:res.user,mobile:"
msgid "Phone number that supports receiving SMS."
msgstr ""
msgctxt "model:ir.message,text:msg_sms_text"
msgid "%(name)s code %(code)s"
msgstr ""
msgctxt "model:ir.message,text:msg_user_sms_code"
msgid "SMS Code for %(login)s"
msgstr ""
msgctxt "model:res.user.login.sms_code,name:"
msgid "SMS Code"
msgstr ""

View File

@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data grouped="1">
<record model="ir.message" id="msg_sms_text">
<field name="text">%(name)s code %(code)s</field>
</record>
<record model="ir.message" id="msg_user_sms_code">
<field name="text">SMS Code for %(login)s</field>
</record>
</data>
</tryton>

115
modules/authentication_sms/res.py Executable file
View File

@@ -0,0 +1,115 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime
import logging
import random
from trytond.config import config
from trytond.exceptions import LoginException
from trytond.i18n import gettext
from trytond.model import Index, ModelSQL, fields
from trytond.pool import Pool, PoolMeta
from trytond.tools import resolve
logger = logging.getLogger(__name__)
def send_sms(text, to):
if config.has_option('authentication_sms', 'function'):
func = resolve(config.get('authentication_sms', 'function'))
if func:
from_ = config.get('authentication_sms', 'from', default=None)
return func(text, to, from_)
logger.error('Could not send SMS to %s: "%s"', to, text)
class User(metaclass=PoolMeta):
__name__ = 'res.user'
mobile = fields.Char('Mobile',
help='Phone number that supports receiving SMS.')
@classmethod
def __setup__(cls):
super(User, cls).__setup__()
cls._preferences_fields.append('mobile')
@classmethod
def _login_sms(cls, login, parameters):
pool = Pool()
SMSCode = pool.get('res.user.login.sms_code')
user_id = cls._get_login(login)[0]
if user_id:
SMSCode.send(user_id)
if 'sms_code' in parameters:
code = parameters['sms_code']
if not code:
return
if SMSCode.check(user_id, code):
return user_id
msg = SMSCode.fields_get(['code'])['code']['string']
msg = gettext('authentication_sms.msg_user_sms_code', login=login)
raise LoginException('sms_code', msg, type='char')
class UserLoginSMSCode(ModelSQL):
"""SMS Code
This class is separated from the res.user one in order to prevent locking
the res.user table when in a long running process.
"""
__name__ = 'res.user.login.sms_code'
user_id = fields.Integer("User ID")
user = fields.Function(fields.Many2One('res.user', 'User'), 'get_user')
code = fields.Char('Code')
@classmethod
def __setup__(cls):
super().__setup__()
t = cls.__table__()
cls._sql_indexes.add(Index(t, (t.user_id, Index.Equality())))
@classmethod
def default_code(cls):
length = config.getint('authentication_sms', 'length', default=6)
srandom = random.SystemRandom()
return ''.join(str(srandom.randint(0, 9)) for _ in range(length))
def get_user(self, name):
return self.user_id
@classmethod
def get(cls, user, _now=None):
if _now is None:
_now = datetime.datetime.now()
timeout = datetime.timedelta(
seconds=config.getint('authentication_sms', 'ttl', default=5 * 60))
records = cls.search([
('user_id', '=', user),
])
for record in records:
if abs(record.create_date - _now) < timeout:
yield record
else:
cls.delete([record])
@classmethod
def send(cls, user, mobile=None):
if not list(cls.get(user)) or mobile:
record = cls(user_id=user)
record.save()
name = config.get('authentication_sms', 'name', default='Tryton')
text = gettext('authentication_sms.msg_sms_text',
name=name, code=record.code)
if mobile:
send_sms(text, mobile)
elif record.user.mobile:
send_sms(text, record.user.mobile)
@classmethod
def check(cls, user, code):
for record in cls.get(user):
if record.code == code:
cls.delete([record])
return True
return False

View File

@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<tryton>
<data>
<record model="ir.ui.view" id="user_view_form">
<field name="model">res.user</field>
<field name="inherit" ref="res.user_view_form"/>
<field name="name">user_form</field>
</record>
<record model="ir.ui.view" id="user_view_form_preferences">
<field name="model">res.user</field>
<field name="inherit" ref="res.user_view_form_preferences"/>
<field name="name">user_form_preferences</field>
</record>
</data>
</tryton>

View File

@@ -0,0 +1,5 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from .test_module import send_sms
__all__ = ['send_sms']

View File

@@ -0,0 +1,117 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime
from trytond.config import config
from trytond.exceptions import LoginException
from trytond.pool import Pool
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
def send_sms(text, to, from_):
sms_queue.append({
'text': text,
'to': to,
'from': from_,
})
sms_queue = []
class AuthenticationSMSTestCase(ModuleTestCase):
'Test Authentication SMS module'
module = 'authentication_sms'
def setUp(self):
super(AuthenticationSMSTestCase, self).setUp()
methods = config.get('session', 'authentications', default='')
config.set('session', 'authentications', 'sms')
self.addCleanup(config.set, 'session', 'authentications', methods)
config.add_section('authentication_sms')
config.set(
'authentication_sms', 'function',
'.'.join([send_sms.__module__, send_sms.__qualname__]))
self.addCleanup(config.remove_section, 'authentication_sms')
del sms_queue[:]
@with_transaction()
def test_sms_code_default_code(self):
pool = Pool()
SMSCode = pool.get('res.user.login.sms_code')
code = SMSCode.default_code()
self.assertEqual(len(code), 6)
@with_transaction()
def test_sms_code_get(self):
pool = Pool()
SMSCode = pool.get('res.user.login.sms_code')
record, = SMSCode.create([{'user_id': 1}])
records = list(SMSCode.get(1))
self.assertEqual(records, [record])
future = datetime.datetime.now() + datetime.timedelta(10 * 60)
records = list(SMSCode.get(1, _now=future))
self.assertFalse(records)
self.assertFalse(SMSCode.search([]))
@with_transaction()
def test_sms_code_send(self):
pool = Pool()
User = pool.get('res.user')
SMSCode = pool.get('res.user.login.sms_code')
user = User(name='sms', login='sms', mobile='+123456789')
user.save()
SMSCode.send(user.id)
record, = SMSCode.search([])
self.assertEqual(len(sms_queue), 1)
sms, = sms_queue
self.assertEqual(record.user_id, user.id)
self.assertIn(record.code, sms['text'])
self.assertEqual(user.mobile, sms['to'])
# Don't send a second SMS as long as the first is valid
SMSCode.send(user.id)
self.assertEqual(len(sms_queue), 1)
@with_transaction()
def test_sms_code_check(self):
pool = Pool()
SMSCode = pool.get('res.user.login.sms_code')
record, = SMSCode.create([{'user_id': 1}])
sms_code = record.code
self.assertFalse(SMSCode.check(1, 'foo'))
self.assertTrue(SMSCode.check(1, sms_code))
# Second check should fail
self.assertFalse(SMSCode.check(1, sms_code))
@with_transaction()
def test_user_get_login(self):
pool = Pool()
User = pool.get('res.user')
SMSCode = pool.get('res.user.login.sms_code')
user = User(name='sms', login='sms', mobile='+123456789')
user.save()
with self.assertRaises(LoginException) as cm:
User.get_login('sms', {})
self.assertEqual(cm.exception.name, 'sms_code')
self.assertEqual(cm.exception.type, 'char')
record, = SMSCode.search([])
sms_code = record.code
user_id = User.get_login('sms', {
'sms_code': sms_code,
})
self.assertEqual(user_id, user.id)
del ModuleTestCase

View File

@@ -0,0 +1,8 @@
[tryton]
version=7.2.1
depends:
ir
res
xml:
res.xml
message.xml

View File

@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<data>
<xpath expr="//field[@name='email']" position="after">
<label name="mobile"/>
<field name="mobile"/>
<newline/>
</xpath>
</data>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<data>
<xpath expr="//field[@name='password']" position="after">
<label name="mobile"/>
<field name="mobile"/>
<newline/>
</xpath>
</data>