Merge branch 'master' into Develop

# Conflicts:
#	cps/templates/list.html
#	cps/translations/cs/LC_MESSAGES/messages.po
#	cps/translations/de/LC_MESSAGES/messages.po
#	cps/translations/es/LC_MESSAGES/messages.po
#	cps/translations/fi/LC_MESSAGES/messages.po
#	cps/translations/fr/LC_MESSAGES/messages.po
#	cps/translations/hu/LC_MESSAGES/messages.po
#	cps/translations/it/LC_MESSAGES/messages.po
#	cps/translations/ja/LC_MESSAGES/messages.po
#	cps/translations/km/LC_MESSAGES/messages.po
#	cps/translations/nl/LC_MESSAGES/messages.po
#	cps/translations/pl/LC_MESSAGES/messages.po
#	cps/translations/ru/LC_MESSAGES/messages.po
#	cps/translations/sv/LC_MESSAGES/messages.po
#	cps/translations/uk/LC_MESSAGES/messages.po
#	cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po
#	messages.pot
This commit is contained in:
Ozzieisaacs 2020-04-25 20:06:25 +02:00
commit b4d7733e0a
35 changed files with 6861 additions and 4400 deletions

49
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,49 @@
## How to contribute to Calibre-Web
First of all, we would like to thank you for reading this text. we are happy you are willing to contribute to Calibre-Web
### **General**
**Communication language** is english. Google translated texts are not as bad as you might think, they are usually understandable, so don't worry if you generate your post that way.
**Calibre-Web** is not **Calibre**. If you are having a question regarding Calibre please post this at their [repository](https://github.com/kovidgoyal/calibre).
**Docker-Containers** of Calibre-Web are maintained by different persons than the people who drive Calibre-Web. If we come to the conclusion during our analysis that the problem is related to Docker, we might ask you to open a new issue at the reprository of the Docker Container.
If you are having **Basic Installation Problems** with python or it's dependencies, please consider using your favorite search engine to find a solution. In case you can't find a solution, we are happy to help you.
We can offer only very limited support regarding configuration of **Reverse-Proxy Installations**, **OPDS-Reader** or other programs in combination with Calibre-Web.
### **Translation**
Some of the user languages in Calibre-Web having missing translations. We are happy to add the missing texts if you are translate them. Create a Pull Request, create an issue with the .po file attached, or write an email to "ozzie.fernandez.isaacs@googlemail.com" with attached translation file. To display all book languages in your native language an additional file is used (iso_language_names.py). The content of this file is autogenerated with the corresponding translations of Calibre, please do not edit this file on your own.
### **Documentation**
The Calibre-Web documentation is hosted in the Github [Wiki](https://github.com/janeczku/calibre-web/wiki). The Wiki is open to everybody, if you find a problem, feel free to correct it. If information is missing, you are welcome to add it. The content will be reviewed time by time. Please try to be consitent with the form with the other Wiki pages (e.g. the project name is Calibre-Web with 2 capital letters and a dash in between).
### **Reporting a bug**
Do not open up a GitHub issue if the bug is a **security vulnerability** in Calibre-Web. Please write intead an email to "ozzie.fernandez.isaacs@googlemail.com".
Ensure the ***bug was not already reported** by searching on GitHub under [Issues](https://github.com/janeczku/calibre-web/issues). Please also check if a solution for your problem can be found in the [wiki](https://github.com/janeczku/calibre-web/wiki).
If you're unable to find an **open issue** addressing the problem, open a [new one](https://github.com/janeczku/calibre-web/issues/new?assignees=&labels=&template=bug_report.md&title=). Be sure to include a **title** and **clear description**, as much relevant information as possible, the **issue form** helps you providing the right information. Deleting the form and just pasting the stack trace doesn't speed up fixing the problem. If your issue could be resolved, consider closing the issue.
### **Feature Request**
If there is afeature missing in Calibre-Web and you can't find a feature request in the [Issues](https://github.com/janeczku/calibre-web/issues) section, you could create a [feature request](https://github.com/janeczku/calibre-web/issues/new?assignees=&labels=&template=feature_request.md&title=).
We will not extend Calibre-Web with any more login abilitys or add further files storages, or file syncing ability. Furthermore Calibre-Web is made for home usage for company inhouse usage, so requests regarding any sorts of social interaction capability, payment routines, search engine or web site analytics integration will not be implemeted.
### **Contributing code to Calibre-Web**
Open a new GitHub pull request with the patch. Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
In case your code enhances features of Calibre-Web: Create your pull request for the development branch if your enhancement consits of more than some lines of code in a local section of Calibre-Webs code. This makes it easier to test it and check all implication before it's made public.
Please check if your code runs on Python 2.7 (still necessary in 2020) and mainly on python 3. If possible and the feature is related to operating system functions, try to check it on Windows and Linux.
Calibre-Web is automatically tested on Linux in combination with python 3.7. The code for testing is in a [seperate repo](https://github.com/OzzieIsaacs/calibre-web-test) on Github. It uses unittest and performs real system tests with selenium, would be great if you could consider also writing some tests.
A static code analysis is done by Codacy, but it's partly broken and doesn't run automatically. You could check your code with ESLint before contributing, a configuration file can be found in the projects root folder.

View File

@ -12,7 +12,7 @@ Calibre-Web is a web app providing a clean interface for browsing, reading and d
- full graphical setup - full graphical setup
- User management with fine-grained per-user permissions - User management with fine-grained per-user permissions
- Admin interface - Admin interface
- User Interface in czech, dutch, english, finnish, french, german, hungarian, italian, japanese, khmer, polish, russian, simplified chinese, spanish, swedish, ukrainian - User Interface in czech, dutch, english, finnish, french, german, hungarian, italian, japanese, khmer, polish, russian, simplified chinese, spanish, swedish, turkish, ukrainian
- OPDS feed for eBook reader apps - OPDS feed for eBook reader apps
- Filter and search by titles, authors, tags, series and language - Filter and search by titles, authors, tags, series and language
- Create a custom book collection (shelves) - Create a custom book collection (shelves)

View File

@ -547,7 +547,7 @@ def _configuration_update_helper():
if config.config_login_type == constants.LOGIN_LDAP: if config.config_login_type == constants.LOGIN_LDAP:
reboot_required |= _config_string("config_ldap_provider_url") reboot_required |= _config_string("config_ldap_provider_url")
reboot_required |= _config_int("config_ldap_port") reboot_required |= _config_int("config_ldap_port")
# _config_string("config_ldap_schema") reboot_required |= _config_int("config_ldap_authentication")
reboot_required |= _config_string("config_ldap_dn") reboot_required |= _config_string("config_ldap_dn")
reboot_required |= _config_string("config_ldap_serv_username") reboot_required |= _config_string("config_ldap_serv_username")
reboot_required |= _config_string("config_ldap_user_object") reboot_required |= _config_string("config_ldap_user_object")
@ -569,9 +569,13 @@ def _configuration_update_helper():
return _configuration_result(_('Please Enter a LDAP Provider, ' return _configuration_result(_('Please Enter a LDAP Provider, '
'Port, DN and User Object Identifier'), gdriveError) 'Port, DN and User Object Identifier'), gdriveError)
if config.config_ldap_authentication > constants.LDAP_AUTH_ANONYMOUS:
if not config.config_ldap_serv_username or not bool(config.config_ldap_serv_password): if config.config_ldap_authentication > constants.LDAP_AUTH_UNAUTHENTICATE:
return _configuration_result('Please Enter a LDAP Service Account and Password', gdriveError) if not config.config_ldap_serv_username or not bool(config.config_ldap_serv_password):
return _configuration_result('Please Enter a LDAP Service Account and Password', gdriveError)
else:
if not config.config_ldap_serv_username:
return _configuration_result('Please Enter a LDAP Service Account', gdriveError)
#_config_checkbox("config_ldap_use_ssl") #_config_checkbox("config_ldap_use_ssl")
#_config_checkbox("config_ldap_use_tls") #_config_checkbox("config_ldap_use_tls")
@ -830,9 +834,8 @@ def edit_user(user_id):
if request.method == "POST": if request.method == "POST":
to_save = request.form.to_dict() to_save = request.form.to_dict()
if "delete" in to_save: if "delete" in to_save:
if ub.session.query(ub.User).filter(and_(ub.User.role.op('&') if ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN,
(constants.ROLE_ADMIN)== constants.ROLE_ADMIN, ub.User.id != content.id).count():
ub.User.id != content.id)).count():
ub.session.query(ub.User).filter(ub.User.id == content.id).delete() ub.session.query(ub.User).filter(ub.User.id == content.id).delete()
ub.session.commit() ub.session.commit()
flash(_(u"User '%(nick)s' deleted", nick=content.nickname), category="success") flash(_(u"User '%(nick)s' deleted", nick=content.nickname), category="success")
@ -841,6 +844,12 @@ def edit_user(user_id):
flash(_(u"No admin user remaining, can't delete user", nick=content.nickname), category="error") flash(_(u"No admin user remaining, can't delete user", nick=content.nickname), category="error")
return redirect(url_for('admin.admin')) return redirect(url_for('admin.admin'))
else: else:
if not ub.session.query(ub.User).filter(ub.User.role.op('&')(constants.ROLE_ADMIN) == constants.ROLE_ADMIN,
ub.User.id != content.id).count() and \
not 'admin_role' in to_save:
flash(_(u"No admin user remaining, can't remove admin role", nick=content.nickname), category="error")
return redirect(url_for('admin.admin'))
if "password" in to_save and to_save["password"]: if "password" in to_save and to_save["password"]:
content.password = generate_password_hash(to_save["password"]) content.password = generate_password_hash(to_save["password"])
anonymous = content.is_anonymous anonymous = content.is_anonymous

View File

@ -95,12 +95,10 @@ class _Settings(_Base):
config_ldap_provider_url = Column(String, default='example.org') config_ldap_provider_url = Column(String, default='example.org')
config_ldap_port = Column(SmallInteger, default=389) config_ldap_port = Column(SmallInteger, default=389)
# config_ldap_schema = Column(String, default='ldap') config_ldap_authentication = Column(SmallInteger, default=constants.LDAP_AUTH_SIMPLE)
config_ldap_serv_username = Column(String, default='cn=admin,dc=example,dc=org') config_ldap_serv_username = Column(String, default='cn=admin,dc=example,dc=org')
config_ldap_serv_password = Column(String, default="") config_ldap_serv_password = Column(String, default="")
config_ldap_encryption = Column(SmallInteger, default=0) config_ldap_encryption = Column(SmallInteger, default=0)
# config_ldap_use_tls = Column(Boolean, default=False)
# config_ldap_require_cert = Column(Boolean, default=False)
config_ldap_cert_path = Column(String, default="") config_ldap_cert_path = Column(String, default="")
config_ldap_dn = Column(String, default='dc=example,dc=org') config_ldap_dn = Column(String, default='dc=example,dc=org')
config_ldap_user_object = Column(String, default='uid=%s') config_ldap_user_object = Column(String, default='uid=%s')

View File

@ -93,7 +93,10 @@ AUTO_UPDATE_NIGHTLY = 1 << 2
LOGIN_STANDARD = 0 LOGIN_STANDARD = 0
LOGIN_LDAP = 1 LOGIN_LDAP = 1
LOGIN_OAUTH = 2 LOGIN_OAUTH = 2
# LOGIN_OAUTH_GOOGLE = 3
LDAP_AUTH_ANONYMOUS = 0
LDAP_AUTH_UNAUTHENTICATE = 1
LDAP_AUTH_SIMPLE = 0
DEFAULT_MAIL_SERVER = "mail.example.org" DEFAULT_MAIL_SERVER = "mail.example.org"

View File

@ -8,6 +8,8 @@
from __future__ import unicode_literals from __future__ import unicode_literals
# This file is autogenerated, do NOT add, change, or delete ANY string
# If you need help or assistance for adding a new language, please contact the project team
# map iso639 language codes to language names, translated # map iso639 language codes to language names, translated
@ -852,6 +854,379 @@ LANGUAGE_NAMES = {
"zxx": "Geen linguïstische inhoud", "zxx": "Geen linguïstische inhoud",
"zza": "Zaza" "zza": "Zaza"
}, },
"tr": {
"abk": "Abhazca",
"ace": "Achinese",
"ach": "Acoli",
"ada": "Adangme",
"ady": "Adyghe",
"aar": "Afar",
"afh": "Afrihili",
"afr": "Afrikanca",
"ain": "Ainu (Japonca)",
"aka": "Akanca (Afrika dili)",
"akk": "Akatça",
"sqi": "Albanian",
"ale": "Alaskaca",
"amh": "Etiyopyaca",
"anp": "Angika",
"ara": "Arapça",
"arg": "Aragonca (İspanya)",
"arp": "Arapaho (Kuzey Amerika yerlileri)",
"arw": "Arawak (Surinam)",
"hye": "Ermenice",
"asm": "Assamese (Hindistan)",
"ast": "Asturyasca",
"ava": "Avarca",
"ave": "Avestan (Eski İran)",
"awa": "Awadhi (Hindistan)",
"aym": "Aymara (Güney Amerika)",
"aze": "Azerice",
"ban": "Balice (Bali adaları)",
"bal": "Belucice (İran)",
"bam": "Bambara (Mali)",
"bas": "Basa (Kamerun)",
"bak": "Başkırca",
"eus": "Baskça",
"bej": "Beja (Eritre; Sudan)",
"bel": "Beyaz Rusça",
"bem": "Bemba (Zambia)",
"ben": "Bengalce",
"bho": "Bhojpuri (Hindistan)",
"bik": "Bikol (Filipinler)",
"byn": "Bilin",
"bin": "Bini (Afrika)",
"bis": "Bislama (Vanuatu; Kuzey Pasifik)",
"zbl": "Blis Sembolleri",
"bos": "Boşnakça",
"bra": "Braj (Hindistan)",
"bre": "Bretonca",
"bug": "Buginese (Endonezya)",
"bul": "Bulgarca",
"bua": "Buriat (Moğolistan)",
"mya": "Burmaca",
"cad": "Caddo (Kuzey Amerika yerlileri)",
"cat": "Katalanca",
"ceb": "Cebuano (Filipinler)",
"chg": "Çağatayca",
"cha": "Chamorro (Guam adaları)",
"che": "Çeçence",
"chr": "Cherokee (Kuzey Amerika yerlileri)",
"chy": "Cheyenne (kuzey Amerika yerlileri)",
"chb": "Chibcha (Kolombiya)",
"zho": "Çince",
"chn": "Chinook lehçesi (Kuzey Batı Amerika kıyıları)",
"chp": "Chipewyan (Kuzey Amerika yerlileri)",
"cho": "Choctaw (Kuzey Amerika yerlileri)",
"chk": "Chuukese",
"chv": "Çuvaş (Türkçe)",
"cop": "Kıptice (Eski Mısır)",
"cor": "Cornish (Kelt)",
"cos": "Korsikaca",
"cre": "Cree (Kuzey Amerika yerlileri)",
"mus": "Creek",
"hrv": "Hırvatça",
"ces": "Çekçe",
"dak": "Dakota (Kuzey Amerika yerlileri)",
"dan": "Danimarkaca; Danca",
"dar": "Dargwa (Dağıstan)",
"del": "Delaware (Kuzey Amerika yerlileri)",
"div": "Dhivehi",
"din": "Dinka (Sudan)",
"doi": "Dogri (makro dili)",
"dgr": "Dogrib (Kanada)",
"dua": "Duala (Afrika)",
"nld": "Flâmanca (Hollanda dili)",
"dyu": "Dyula (Burkina Faso; Mali)",
"dzo": "Dzongkha (Butan)",
"efi": "Efik (Afrika)",
"egy": "Mısırca (Eski)",
"eka": "Ekajuk (Afrika)",
"elx": "Elamca",
"eng": "İngilizce",
"myv": "Erzya dili",
"epo": "Esperanto",
"est": "Estonca",
"ewe": "Ewe (Afrika)",
"ewo": "Ewondo (Afrika)",
"fan": "Fang (Ekvatoryal Guinea)",
"fat": "Fanti (Afrika)",
"fao": "Faroece",
"fij": "Fiji dili",
"fil": "Filipince",
"fin": "Fince",
"fon": "Fon (Benin)",
"fra": "Fransızca",
"fur": "Friulian (İtalya)",
"ful": "Fulah (Afrika)",
"gaa": "Ganaca",
"glg": "Galce",
"lug": "Ganda Dili",
"gay": "Gayo (Sumatra)",
"gba": "Gbaya (Orta Afrika Cumhuriyeti)",
"gez": "Geez (Etiyopya)",
"kat": "Gürcüce",
"deu": "Almanca",
"gil": "Kiribati dili",
"gon": "Gondi (Hindistan)",
"gor": "Gorontalo (Endonezya)",
"got": "Gotik",
"grb": "Grebo (Liberya)",
"grn": "Guarani (Paraguay)",
"guj": "Gucaratça",
"gwi": "Gwichʼin",
"hai": "Haida (Kuzey Amerika yerlileri)",
"hau": "Hausa Dili",
"haw": "Havai Dili",
"heb": "İbranice",
"her": "Herero Dili",
"hil": "Hiligaynon",
"hin": "Hintçe",
"hmo": "Hiri Motu",
"hit": "Hititçe",
"hmn": "Hmong",
"hun": "Macarca",
"hup": "Hupa",
"iba": "Iban",
"isl": "İzlandaca",
"ido": "Ido Dili",
"ibo": "Igbo Dili",
"ilo": "Iloko",
"ind": "Endonezyaca",
"inh": "İnguşca",
"ina": "Interlingua (Uluslararası Yardımcı Dil Kurumu)",
"ile": "Interlingue",
"iku": "Inuktitut",
"ipk": "Inupiak Dili",
"gle": "İrlandaca",
"ita": "İtalyanca",
"jpn": "Japonca",
"jav": "Cava Dili",
"jrb": "Yahudi-Arapçası",
"jpr": "Yahudi-Farsça",
"kbd": "Kabardian",
"kab": "Kabyle",
"kac": "Kachin",
"kal": "Kalaallisut",
"xal": "Kalmyk",
"kam": "Kamba (Kenya)",
"kan": "Kannada",
"kau": "Kanuri Dili",
"kaa": "Kara-Kalpak",
"krc": "Karachay-Balkar",
"krl": "Karelian",
"kas": "Keşmirce",
"csb": "Kashubian (Lehçe diyalekti)",
"kaw": "Kawi",
"kaz": "Kazakça",
"kha": "Khasi",
"kho": "Khotanese",
"kik": "Kikuyu Dili",
"kmb": "Kimbundu",
"kin": "Kinyarwanda",
"kir": "Kırgızca",
"tlh": "Klingon",
"kom": "Komi Dili",
"kon": "Kongo Dili",
"kok": "Konkani (makro dil)",
"kor": "Korece",
"kos": "Kosraean",
"kpe": "Kpelle",
"kua": "Kuanyama Dili",
"kum": "Kumyk",
"kur": "Kürtçe",
"kru": "Kurukh",
"kut": "Kutenai",
"lad": "Ladino",
"lah": "Lahnda",
"lam": "Lamba",
"lao": "Laos Dili",
"lat": "Latince",
"lav": "Letonca",
"lez": "Lezghian",
"lim": "Liburg Dili",
"lin": "Lingala Dili",
"lit": "Litvanyaca",
"jbo": "Lojban dili",
"loz": "Lozi",
"lub": "Luba Katanga Dili",
"lua": "Luba-Lulua",
"lui": "Luiseno",
"smj": "Lule Sami",
"lun": "Lunda",
"luo": "Luo (Kenya ve Tanzanya)",
"lus": "Lushai",
"ltz": "Lüksemburg Dili",
"mkd": "Makedonca",
"mad": "Madurese",
"mag": "Magahi",
"mai": "Maithili dili",
"mak": "Makasar",
"mlg": "Madagaskar Dili",
"msa": "Malay (makro dili)",
"mal": "Malayalam",
"mlt": "Maltaca",
"mnc": "Manchu",
"mdr": "Mandar",
"man": "Mandingo",
"mni": "Manipuri dili",
"glv": "Manx (Galler)",
"mri": "Maori Dili",
"arn": "Mapudungun",
"mar": "Marathi",
"chm": "Mari (Rusya)",
"mah": "Marshall Dili",
"mwr": "Marwari",
"mas": "Masai",
"men": "Mende (Sierra Leone)",
"mic": "Mi'kmak",
"min": "Minangkabau",
"mwl": "Mirandese",
"moh": "Mohawk",
"mdf": "Moşka",
"lol": "Mongo",
"mon": "Moğol Dili",
"mos": "Mossi",
"mul": "Çoklu diller",
"nqo": "N'Ko",
"nau": "Nauru",
"nav": "Navajo Dili",
"ndo": "Ndonga Dili",
"nap": "Neapolitan",
"nia": "Nias",
"niu": "Niuean",
"zxx": "Hiçbir dil içeriği yok",
"nog": "Nogai",
"nor": "Norveçce",
"nob": "Norveççe Bokmal",
"nno": "Norveççe Nynorsk",
"nym": "Nyamwezi",
"nya": "Nyanja",
"nyn": "Nyankole",
"nyo": "Nyoro",
"nzi": "Nzima",
"oci": "Oksitanca (1500 sonrası)",
"oji": "Ojibwa Dili",
"orm": "Oromo Dili",
"osa": "Osage",
"oss": "Osetya Dili",
"pal": "Pehlevi",
"pau": "Palauan",
"pli": "Pali Dili",
"pam": "Pampanga",
"pag": "Pangasinan",
"pan": "Pencabi Dili",
"pap": "Papiamento",
"fas": "Farsça",
"phn": "Fenikçe",
"pon": "Pohnpeian",
"pol": "Polonyaca",
"por": "Portekizce",
"pus": "Pushto",
"que": "Quechua",
"raj": "Rajasthani",
"rap": "Rapanui",
"ron": "Rumence",
"roh": "Romanca",
"rom": "Çingene Dili",
"run": "Kirundi",
"rus": "Rusça",
"smo": "Samoa Dili",
"sad": "Sandawe",
"sag": "Sangho",
"san": "Sanskritçe",
"sat": "Santali dili",
"srd": "Sardinya",
"sas": "Sasak",
"sco": "İskoç lehçesi",
"sel": "Selkup",
"srp": "Sırpça",
"srr": "Serer",
"shn": "Shan",
"sna": "Shona",
"scn": "Sicilyalı",
"sid": "Sidamo",
"bla": "Siksika (Kuzey Amerika yerlileri)",
"snd": "Sindhi",
"sin": "Sinhala Dili",
"den": "Slave (Athapascan; Kuzey Amerika yerlileri)",
"slk": "Slovakça",
"slv": "Slovence",
"sog": "Sogdian",
"som": "Somali Dili",
"snk": "Soninke",
"spa": "İspanyolca",
"srn": "Sranan Tongo",
"suk": "Sukuma",
"sux": "Sümerce",
"sun": "Sudan Dili",
"sus": "Susu",
"swa": "Swahili (makro dil)",
"ssw": "Siswati",
"swe": "İsveçce",
"syr": "Süryanice",
"tgl": "Tagalog",
"tah": "Tahitice",
"tgk": "Tacikçe",
"tmh": "Tamashek",
"tam": "Tamilce",
"tat": "Tatarca",
"tel": "Telugu",
"ter": "Tereno",
"tet": "Tetum",
"tha": "Taylandça",
"bod": "Tibetçe",
"tig": "Tigre",
"tir": "Tigrinya Dili",
"tem": "Timne",
"tiv": "Tiv",
"tli": "Tlingit",
"tpi": "Tok Pisin",
"tkl": "Tokelau",
"tog": "Tonga (Nyasa)",
"ton": "Tonga",
"tsi": "Tsimshian",
"tso": "Tsonga",
"tsn": "Setswana",
"tum": "Tumbuka",
"tur": "Türkçe",
"tuk": "Türkmence",
"tvl": "Tuvalu",
"tyv": "Tuvinian",
"twi": "Twi",
"udm": "Udmurt",
"uga": "Ugarit Çivi Yazısı",
"uig": "Uygurca",
"ukr": "Ukraynaca",
"umb": "Umbundu",
"mis": "Şifresiz diller",
"und": "Belirlenemeyen",
"urd": "Urduca",
"uzb": "Özbekçe",
"vai": "Vai",
"ven": "Venda Dili",
"vie": "Vietnamca",
"vol": "Volapük",
"vot": "Votic",
"wln": "Valonca",
"war": "Waray (Filipinler)",
"was": "Vasho",
"cym": "Gal Dili",
"wal": "Wolaytta",
"wol": "Wolof",
"xho": "Xhosa",
"sah": "Yakut",
"yao": "Yao",
"yap": "Yapese",
"yid": "Yidiş",
"yor": "Yoruba",
"zap": "Zapotec",
"zza": "Zaza",
"zen": "Zenaga",
"zha": "Zuang Dili",
"zul": "Zulu",
"zun": "Zuni"
},
"fr": { "fr": {
"aar": "afar", "aar": "afar",
"abk": "abkhaze", "abk": "abkhaze",
@ -4935,7 +5310,7 @@ LANGUAGE_NAMES = {
"pon": "Pohnpeian", "pon": "Pohnpeian",
"por": "Portuguese", "por": "Portuguese",
"pro": "Provençal; Old (to 1500)", "pro": "Provençal; Old (to 1500)",
"pus": "Pushto", "pus": "Pashto",
"que": "Quechua", "que": "Quechua",
"raj": "Rajasthani", "raj": "Rajasthani",
"rap": "Rapanui", "rap": "Rapanui",
@ -6195,7 +6570,7 @@ LANGUAGE_NAMES = {
"pon": "Pohnpeian", "pon": "Pohnpeian",
"por": "Portuguese", "por": "Portuguese",
"pro": "Provençal; Old (to 1500)", "pro": "Provençal; Old (to 1500)",
"pus": "Pushto", "pus": "Pashto",
"que": "Quechua", "que": "Quechua",
"raj": "Rajasthani", "raj": "Rajasthani",
"rap": "Rapanui", "rap": "Rapanui",
@ -6615,7 +6990,7 @@ LANGUAGE_NAMES = {
"pon": "Pohnpeian", "pon": "Pohnpeian",
"por": "Portuguese", "por": "Portuguese",
"pro": "Provençal; Old (to 1500)", "pro": "Provençal; Old (to 1500)",
"pus": "Pushto", "pus": "Pashto",
"que": "Quechua", "que": "Quechua",
"raj": "Rajasthani", "raj": "Rajasthani",
"rap": "Rapanui", "rap": "Rapanui",

View File

@ -42,11 +42,17 @@ def init_app(app, config):
app.config['LDAP_SCHEMA'] = 'ldaps' app.config['LDAP_SCHEMA'] = 'ldaps'
else: else:
app.config['LDAP_SCHEMA'] = 'ldap' app.config['LDAP_SCHEMA'] = 'ldap'
# app.config['LDAP_SCHEMA'] = config.config_ldap_schema if config.config_ldap_authentication > constants.LDAP_AUTH_ANONYMOUS:
app.config['LDAP_USERNAME'] = config.config_ldap_serv_username if config.config_ldap_authentication > constants.LDAP_AUTH_UNAUTHENTICATE:
if config.config_ldap_serv_password is None: if config.config_ldap_serv_password is None:
config.config_ldap_serv_password = '' config.config_ldap_serv_password = ''
app.config['LDAP_PASSWORD'] = base64.b64decode(config.config_ldap_serv_password) app.config['LDAP_PASSWORD'] = base64.b64decode(config.config_ldap_serv_password)
else:
app.config['LDAP_PASSWORD'] = base64.b64decode("")
app.config['LDAP_USERNAME'] = config.config_ldap_serv_username
else:
app.config['LDAP_USERNAME'] = ""
app.config['LDAP_PASSWORD'] = base64.b64decode("")
if bool(config.config_ldap_cert_path): if bool(config.config_ldap_cert_path):
app.config['LDAP_REQUIRE_CERT'] = True app.config['LDAP_REQUIRE_CERT'] = True
app.config['LDAP_CERT_PATH'] = config.config_ldap_cert_path app.config['LDAP_CERT_PATH'] = config.config_ldap_cert_path
@ -90,7 +96,7 @@ def bind_user(username, password):
log.debug("LDAP login '%s': %r", username, result) log.debug("LDAP login '%s': %r", username, result)
return result is not None, None return result is not None, None
return None, None # User not found return None, None # User not found
except (TypeError, AttributeError) as ex: except (TypeError, AttributeError, KeyError) as ex:
error = ("LDAP bind_user: %s" % ex) error = ("LDAP bind_user: %s" % ex)
return None, error return None, error
except LDAPException as ex: except LDAPException as ex:

View File

@ -73,9 +73,9 @@ $(function () {
if (showFlag === 1) { if (showFlag === 1) {
$("#meta-info").html("<ul id=\"book-list\" class=\"media-list\"></ul>"); $("#meta-info").html("<ul id=\"book-list\" class=\"media-list\"></ul>");
} }
if ((ggDone == 3 || (ggDone == 1 && ggResults.length === 0)) && if ((ggDone === 3 || (ggDone === 1 && ggResults.length === 0)) &&
(dbDone == 3 || (ggDone == 1 && dbResults.length === 0)) && (dbDone === 3 || (ggDone === 1 && dbResults.length === 0)) &&
(cvDone == 3 || (ggDone == 1 && cvResults.length === 0))) { (cvDone === 3 || (ggDone === 1 && cvResults.length === 0))) {
$("#meta-info").html("<p class=\"text-danger\">" + msg.no_result + "</p>"); $("#meta-info").html("<p class=\"text-danger\">" + msg.no_result + "</p>");
return; return;
} }
@ -191,7 +191,7 @@ $(function () {
var dateFomers = ""; var dateFomers = "";
if (result.store_date) { if (result.store_date) {
dateFomers = result.store_date.split("-"); dateFomers = result.store_date.split("-");
}else{ } else {
dateFomers = result.date_added.split("-"); dateFomers = result.date_added.split("-");
} }
var publishedYear = parseInt(dateFomers[0]); var publishedYear = parseInt(dateFomers[0]);
@ -202,12 +202,12 @@ $(function () {
var book = { var book = {
id: result.id, id: result.id,
title: seriesTitle + ' #' +('00' + result.issue_number).slice(-3) + ' - ' + result.name, title: seriesTitle + " #" + ("00" + result.issue_number).slice(-3) + " - " + result.name,
authors: result.author || [], authors: result.author || [],
description: result.description, description: result.description,
publisher: "", publisher: "",
publishedDate: publishedDate || "", publishedDate: publishedDate || "",
tags: ['Comics', seriesTitle], tags: ["Comics", seriesTitle],
rating: 0, rating: 0,
series: seriesTitle || "", series: seriesTitle || "",
cover: result.image.original_url, cover: result.image.original_url,

View File

@ -211,8 +211,7 @@ $(function() {
data: {"parameter":2}, data: {"parameter":2},
success: function success(data) { success: function success(data) {
$("#spinner2").hide(); $("#spinner2").hide();
ResultText = data.text; $("#DialogContent").html(data.text);
$("#DialogContent").html(ResultText);
$("#DialogFinished").removeClass("hidden"); $("#DialogFinished").removeClass("hidden");
} }
}); });
@ -298,7 +297,7 @@ $(function() {
$(".discover .row").isotope("layout"); $(".discover .row").isotope("layout");
}); });
$('#import_ldap_users').click(function() { $("#import_ldap_users").click(function() {
$("#DialogHeader").addClass("hidden"); $("#DialogHeader").addClass("hidden");
$("#DialogFinished").addClass("hidden"); $("#DialogFinished").addClass("hidden");
$("#DialogContent").html(""); $("#DialogContent").html("");
@ -311,8 +310,7 @@ $(function() {
url: path + "/../../import_ldap_users", url: path + "/../../import_ldap_users",
success: function success(data) { success: function success(data) {
$("#spinner2").hide(); $("#spinner2").hide();
ResultText = data.text; $("#DialogContent").html(data.text);
$("#DialogContent").html(ResultText);
$("#DialogFinished").removeClass("hidden"); $("#DialogFinished").removeClass("hidden");
} }
}); });

View File

@ -149,12 +149,10 @@ $(function() {
$.ajax({ $.ajax({
url: path + "/../../ajax/editrestriction/" + type, url: path + "/../../ajax/editrestriction/" + type,
type: "Post", type: "Post",
data: row //$(this).closest("form").serialize() + "&" + $(this)[0].name + "=", data: row
}); });
}); });
$("[id^=submit_]").click(function(event) { $("[id^=submit_]").click(function(event) {
// event.stopPropagation();
// event.preventDefault();
$(this)[0].blur(); $(this)[0].blur();
$.ajax({ $.ajax({
url: path + "/../../ajax/addrestriction/" + type, url: path + "/../../ajax/addrestriction/" + type,

View File

@ -233,7 +233,6 @@
<input type="number" min="1" max="65535" class="form-control" id="config_ldap_port" name="config_ldap_port" value="{% if config.config_ldap_port != None %}{{ config.config_ldap_port }}{% endif %}" autocomplete="off" required> <input type="number" min="1" max="65535" class="form-control" id="config_ldap_port" name="config_ldap_port" value="{% if config.config_ldap_port != None %}{{ config.config_ldap_port }}{% endif %}" autocomplete="off" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="config_ldap_encryption">{{_('LDAP Encryption')}}</label>
<label for="config_ldap_encryption">{{_('LDAP Encryption')}}</label> <label for="config_ldap_encryption">{{_('LDAP Encryption')}}</label>
<select name="config_ldap_encryption" id="config_ldap_encryption" class="form-control" data-controlall="ldap-cert-settings"> <select name="config_ldap_encryption" id="config_ldap_encryption" class="form-control" data-controlall="ldap-cert-settings">
<option value="0" {% if config.config_ldap_encryption == 0 %}selected{% endif %}>{{ _('None') }}</option> <option value="0" {% if config.config_ldap_encryption == 0 %}selected{% endif %}>{{ _('None') }}</option>
@ -247,14 +246,25 @@
<input type="text" class="form-control" id="config_ldap_cert_path" name="config_ldap_cert_path" value="{% if config.config_ldap_cert_path != None %}{{ config.config_ldap_cert_path }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" id="config_ldap_cert_path" name="config_ldap_cert_path" value="{% if config.config_ldap_cert_path != None %}{{ config.config_ldap_cert_path }}{% endif %}" autocomplete="off">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="config_ldap_serv_username">{{_('LDAP Administrator Username')}}</label> <label for="config_ldap_authentication">{{_('LDAP Authentication')}}</label>
<input type="text" class="form-control" id="config_ldap_serv_username" name="config_ldap_serv_username" value="{% if config.config_ldap_serv_username != None %}{{ config.config_ldap_serv_username }}{% endif %}" autocomplete="off"> <select name="config_ldap_authentication" id="config_ldap_authentication" class="form-control" data-control="ldap-auth-password" data-controlall="ldap-auth-settings">
<option value="0" {% if config.config_ldap_authentication == 0 %}selected{% endif %}>{{ _('Anonymous') }}</option>
<option value="1" {% if config.config_ldap_authentication == 1 %}selected{% endif %}>{{ _('Unauthenticated') }}</option>
<option value="2" {% if config.config_ldap_authentication == 2 %}selected{% endif %}>{{ _('Simple') }}</option>
</select>
</div> </div>
<div class="form-group"> <div data-related="ldap-auth-settings">
<label for="config_ldap_serv_password">{{_('LDAP Administrator Password')}}</label> <div class="form-group">
<input type="password" class="form-control" id="config_ldap_serv_password" name="config_ldap_serv_password" value="" autocomplete="off"> <label for="config_ldap_serv_username">{{_('LDAP Administrator Username')}}</label>
<input type="text" class="form-control" id="config_ldap_serv_username" name="config_ldap_serv_username" value="{% if config.config_ldap_serv_username != None %}{{ config.config_ldap_serv_username }}{% endif %}" autocomplete="off">
</div>
</div>
<div data-related="ldap-auth-password-2">
<div class="form-group">
<label for="config_ldap_serv_password">{{_('LDAP Administrator Password')}}</label>
<input type="password" class="form-control" id="config_ldap_serv_password" name="config_ldap_serv_password" value="" autocomplete="off">
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="config_ldap_dn">{{_('LDAP Distinguished Name (DN)')}}</label> <label for="config_ldap_dn">{{_('LDAP Distinguished Name (DN)')}}</label>

View File

@ -77,7 +77,7 @@
<div class="form-group"> <div class="form-group">
<input type="checkbox" name="Show_detail_random" id="Show_detail_random" {% if content.show_detail_random() %}checked{% endif %}> <input type="checkbox" name="Show_detail_random" id="Show_detail_random" {% if content.show_detail_random() %}checked{% endif %}>
<label for="Show_detail_random">{{_('Show Random Books')}}</label> <label for="Show_detail_random">{{_('Show Random Books in Detail View')}}</label>
</div> </div>
{% if ( g.user and g.user.role_admin() and not new_user ) %} {% if ( g.user and g.user.role_admin() and not new_user ) %}
<a href="#" id="get_user_tags" class="btn btn-default" data-toggle="modal" data-target="#restrictModal">{{_('Add Allowed/Denied Tags')}}</a> <a href="#" id="get_user_tags" class="btn btn-default" data-toggle="modal" data-target="#restrictModal">{{_('Add Allowed/Denied Tags')}}</a>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -156,6 +156,9 @@ def load_user_from_auth_header(header_val):
except (TypeError, UnicodeDecodeError, binascii.Error): except (TypeError, UnicodeDecodeError, binascii.Error):
pass pass
user = _fetch_user_by_name(basic_username) user = _fetch_user_by_name(basic_username)
if config.config_login_type == constants.LOGIN_LDAP and services.ldap:
if services.ldap.bind_user(str(user.password), basic_password):
return user
if user and check_password_hash(str(user.password), basic_password): if user and check_password_hash(str(user.password), basic_password):
return user return user
return return
@ -285,7 +288,7 @@ def import_ldap_users():
showtext = {} showtext = {}
try: try:
new_users = services.ldap.get_group_members(config.config_ldap_group_name) new_users = services.ldap.get_group_members(config.config_ldap_group_name)
except (services.ldap.LDAPException, TypeError, AttributeError) as e: except (services.ldap.LDAPException, TypeError, AttributeError, KeyError) as e:
log.debug(e) log.debug(e)
showtext['text'] = _(u'Error: %(ldaperror)s', ldaperror=e) showtext['text'] = _(u'Error: %(ldaperror)s', ldaperror=e)
return json.dumps(showtext) return json.dumps(showtext)

File diff suppressed because it is too large Load Diff

View File

@ -17,12 +17,12 @@ goodreads>=0.3.2,<0.4.0
python-Levenshtein>=0.12.0,<0.13.0 python-Levenshtein>=0.12.0,<0.13.0
# ldap login # ldap login
python_ldap>=3.0.0,<3.3.0 python-ldap>=3.0.0,<3.3.0
flask-simpleldap>=1.4.0,<1.5.0 Flask-SimpleLDAP>=1.4.0,<1.5.0
#oauth #oauth
flask-dance>=1.4.0,<3.1.0 Flask-Dance>=1.4.0,<3.1.0
sqlalchemy_utils>=0.33.5,<0.37.0 SQLAlchemy-Utils>=0.33.5,<0.37.0
# extracting metadata # extracting metadata
lxml>=3.8.0,<4.6.0 lxml>=3.8.0,<4.6.0

View File

@ -36,17 +36,17 @@
<div class="col-xs-12 col-sm-6"> <div class="col-xs-12 col-sm-6">
<div class="row"> <div class="row">
<div class="col-xs-6 col-md-6 col-sm-offset-3" style="margin-top:50px;"> <div class="col-xs-6 col-md-6 col-sm-offset-3" style="margin-top:50px;">
<p class='text-justify attribute'><strong>Start Time: </strong>2020-04-15 20:58:24</p> <p class='text-justify attribute'><strong>Start Time: </strong>2020-04-18 10:46:25</p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-6 col-md-6 col-sm-offset-3"> <div class="col-xs-6 col-md-6 col-sm-offset-3">
<p class='text-justify attribute'><strong>Stop Time: </strong>2020-04-15 21:44:34</p> <p class='text-justify attribute'><strong>Stop Time: </strong>2020-04-18 11:34:54</p>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-6 col-md-6 col-sm-offset-3"> <div class="col-xs-6 col-md-6 col-sm-offset-3">
<p class='text-justify attribute'><strong>Duration: </strong>2409.70 s</p> <p class='text-justify attribute'><strong>Duration: </strong>41:54 min</p>
</div> </div>
</div> </div>
</div> </div>
@ -1006,9 +1006,9 @@
<pre class="text-left">Traceback (most recent call last): <pre class="text-left">Traceback (most recent call last):
File "/home/matthias/Entwicklung/calibre-web-test/test/test_kobo_sync.py", line 89, in test_check_sync File "/home/matthias/Entwicklung/calibre-web-test/test/test_kobo_sync.py", line 89, in test_check_sync
self.assertEqual(r.json()['Resources']['image_url_quality_template'], self.kobo_adress+"/{ImageId}/{width}/{height}/image.jpg") self.assertEqual(r.json()['Resources']['image_url_quality_template'], self.kobo_adress+"/{ImageId}/{width}/{height}/image.jpg")
AssertionError: 'http[35 chars]4304a11f244beb23c60f4b7b0/{ImageId}/image.jpg' != 'http[35 chars]4304a11f244beb23c60f4b7b0/{ImageId}/{width}/{height}/image.jpg' AssertionError: 'http[35 chars]65c2703d57c660b93b6ebdafa/{ImageId}/image.jpg' != 'http[35 chars]65c2703d57c660b93b6ebdafa/{ImageId}/{width}/{height}/image.jpg'
- http://192.168.188.33:8083/kobo/1b4c3e84304a11f244beb23c60f4b7b0/{ImageId}/image.jpg - http://192.168.188.33:8083/kobo/8e590a265c2703d57c660b93b6ebdafa/{ImageId}/image.jpg
+ http://192.168.188.33:8083/kobo/1b4c3e84304a11f244beb23c60f4b7b0/{ImageId}/{width}/{height}/image.jpg + http://192.168.188.33:8083/kobo/8e590a265c2703d57c660b93b6ebdafa/{ImageId}/{width}/{height}/image.jpg
? +++++++++++++++++</pre> ? +++++++++++++++++</pre>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
@ -1040,13 +1040,13 @@ AssertionError: 'http[35 chars]4304a11f244beb23c60f4b7b0/{ImageId}/image.jpg' !=
<tr class="result['header']['style']"> <tr class="result['header']['style']">
<td>test_ldap.test_ldap_login</td> <td>test_ldap.test_ldap_login</td>
<td class="text-center">7</td> <td class="text-center">8</td>
<td class="text-center">7</td> <td class="text-center">8</td>
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center"> <td class="text-center">
<a onclick="showClassDetail('c9', 7)">Detail</a> <a onclick="showClassDetail('c9', 8)">Detail</a>
</td> </td>
</tr> </tr>
@ -1114,6 +1114,15 @@ AssertionError: 'http[35 chars]4304a11f244beb23c60f4b7b0/{ImageId}/image.jpg' !=
</tr> </tr>
<tr id='pt9.8' class='hiddenRow bg-success'>
<td>
<div class='testcase'>test_ldap_authentication</div>
</td>
<td colspan='6' align='center'>PASS</td>
</tr>
<tr class="result['header']['style']"> <tr class="result['header']['style']">
@ -1310,14 +1319,14 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr class="result['header']['style']"> <tr class="result['header']['style']">
<td>test_opds_feed.test_opds_feed</td> <td>test_oauth.test_OAuth_login</td>
<td class="text-center">20</td> <td class="text-center">2</td>
<td class="text-center">20</td> <td class="text-center">2</td>
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center"> <td class="text-center">
<a onclick="showClassDetail('c12', 20)">Detail</a> <a onclick="showClassDetail('c12', 2)">Detail</a>
</td> </td>
</tr> </tr>
@ -1325,7 +1334,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.1' class='hiddenRow bg-success'> <tr id='pt12.1' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds</div> <div class='testcase'>test_oauth_about</div>
</td> </td>
<td colspan='6' align='center'>PASS</td> <td colspan='6' align='center'>PASS</td>
</tr> </tr>
@ -1333,6 +1342,39 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.2' class='hiddenRow bg-success'> <tr id='pt12.2' class='hiddenRow bg-success'>
<td>
<div class='testcase'>test_visible_oauth</div>
</td>
<td colspan='6' align='center'>PASS</td>
</tr>
<tr class="result['header']['style']">
<td>test_opds_feed.test_opds_feed</td>
<td class="text-center">20</td>
<td class="text-center">20</td>
<td class="text-center">0</td>
<td class="text-center">0</td>
<td class="text-center">0</td>
<td class="text-center">
<a onclick="showClassDetail('c13', 20)">Detail</a>
</td>
</tr>
<tr id='pt13.1' class='hiddenRow bg-success'>
<td>
<div class='testcase'>test_opds</div>
</td>
<td colspan='6' align='center'>PASS</td>
</tr>
<tr id='pt13.2' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_author</div> <div class='testcase'>test_opds_author</div>
</td> </td>
@ -1341,7 +1383,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.3' class='hiddenRow bg-success'> <tr id='pt13.3' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_calibre_companion</div> <div class='testcase'>test_opds_calibre_companion</div>
</td> </td>
@ -1350,7 +1392,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.4' class='hiddenRow bg-success'> <tr id='pt13.4' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_cover</div> <div class='testcase'>test_opds_cover</div>
</td> </td>
@ -1359,7 +1401,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.5' class='hiddenRow bg-success'> <tr id='pt13.5' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_download_book</div> <div class='testcase'>test_opds_download_book</div>
</td> </td>
@ -1368,7 +1410,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.6' class='hiddenRow bg-success'> <tr id='pt13.6' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_formats</div> <div class='testcase'>test_opds_formats</div>
</td> </td>
@ -1377,7 +1419,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.7' class='hiddenRow bg-success'> <tr id='pt13.7' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_guest_user</div> <div class='testcase'>test_opds_guest_user</div>
</td> </td>
@ -1386,7 +1428,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.8' class='hiddenRow bg-success'> <tr id='pt13.8' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_hot</div> <div class='testcase'>test_opds_hot</div>
</td> </td>
@ -1395,7 +1437,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.9' class='hiddenRow bg-success'> <tr id='pt13.9' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_language</div> <div class='testcase'>test_opds_language</div>
</td> </td>
@ -1404,7 +1446,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.10' class='hiddenRow bg-success'> <tr id='pt13.10' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_non_admin</div> <div class='testcase'>test_opds_non_admin</div>
</td> </td>
@ -1413,7 +1455,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.11' class='hiddenRow bg-success'> <tr id='pt13.11' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_publisher</div> <div class='testcase'>test_opds_publisher</div>
</td> </td>
@ -1422,7 +1464,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.12' class='hiddenRow bg-success'> <tr id='pt13.12' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_random</div> <div class='testcase'>test_opds_random</div>
</td> </td>
@ -1431,7 +1473,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.13' class='hiddenRow bg-success'> <tr id='pt13.13' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_ratings</div> <div class='testcase'>test_opds_ratings</div>
</td> </td>
@ -1440,7 +1482,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.14' class='hiddenRow bg-success'> <tr id='pt13.14' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_read_unread</div> <div class='testcase'>test_opds_read_unread</div>
</td> </td>
@ -1449,7 +1491,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.15' class='hiddenRow bg-success'> <tr id='pt13.15' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_search</div> <div class='testcase'>test_opds_search</div>
</td> </td>
@ -1458,7 +1500,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.16' class='hiddenRow bg-success'> <tr id='pt13.16' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_series</div> <div class='testcase'>test_opds_series</div>
</td> </td>
@ -1467,7 +1509,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.17' class='hiddenRow bg-success'> <tr id='pt13.17' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_shelf_access</div> <div class='testcase'>test_opds_shelf_access</div>
</td> </td>
@ -1476,7 +1518,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.18' class='hiddenRow bg-success'> <tr id='pt13.18' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_tags</div> <div class='testcase'>test_opds_tags</div>
</td> </td>
@ -1485,7 +1527,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.19' class='hiddenRow bg-success'> <tr id='pt13.19' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_opds_top_rated</div> <div class='testcase'>test_opds_top_rated</div>
</td> </td>
@ -1494,7 +1536,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt12.20' class='hiddenRow bg-success'> <tr id='pt13.20' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_recently_added</div> <div class='testcase'>test_recently_added</div>
</td> </td>
@ -1512,13 +1554,13 @@ AssertionError: False is not true : logfile config value is not empty after rese
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center"> <td class="text-center">
<a onclick="showClassDetail('c13', 6)">Detail</a> <a onclick="showClassDetail('c14', 6)">Detail</a>
</td> </td>
</tr> </tr>
<tr id='pt13.1' class='hiddenRow bg-success'> <tr id='pt14.1' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_forgot_password</div> <div class='testcase'>test_forgot_password</div>
</td> </td>
@ -1527,7 +1569,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt13.2' class='hiddenRow bg-success'> <tr id='pt14.2' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_limit_domain</div> <div class='testcase'>test_limit_domain</div>
</td> </td>
@ -1536,7 +1578,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt13.3' class='hiddenRow bg-success'> <tr id='pt14.3' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_register_no_server</div> <div class='testcase'>test_register_no_server</div>
</td> </td>
@ -1545,7 +1587,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt13.4' class='hiddenRow bg-success'> <tr id='pt14.4' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_registering_user</div> <div class='testcase'>test_registering_user</div>
</td> </td>
@ -1554,7 +1596,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt13.5' class='hiddenRow bg-success'> <tr id='pt14.5' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_registering_user_fail</div> <div class='testcase'>test_registering_user_fail</div>
</td> </td>
@ -1563,7 +1605,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt13.6' class='hiddenRow bg-success'> <tr id='pt14.6' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_user_change_password</div> <div class='testcase'>test_user_change_password</div>
</td> </td>
@ -1581,13 +1623,13 @@ AssertionError: False is not true : logfile config value is not empty after rese
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center">1</td> <td class="text-center">1</td>
<td class="text-center"> <td class="text-center">
<a onclick="showClassDetail('c14', 8)">Detail</a> <a onclick="showClassDetail('c15', 8)">Detail</a>
</td> </td>
</tr> </tr>
<tr id='pt14.1' class='hiddenRow bg-success'> <tr id='pt15.1' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_arrange_shelf</div> <div class='testcase'>test_arrange_shelf</div>
</td> </td>
@ -1596,7 +1638,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt14.2' class='hiddenRow bg-success'> <tr id='pt15.2' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_delete_book_of_shelf</div> <div class='testcase'>test_delete_book_of_shelf</div>
</td> </td>
@ -1605,7 +1647,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt14.3' class='hiddenRow bg-success'> <tr id='pt15.3' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_private_shelf</div> <div class='testcase'>test_private_shelf</div>
</td> </td>
@ -1614,7 +1656,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt14.4' class='hiddenRow bg-success'> <tr id='pt15.4' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_public_private_shelf</div> <div class='testcase'>test_public_private_shelf</div>
</td> </td>
@ -1623,7 +1665,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt14.5' class='hiddenRow bg-success'> <tr id='pt15.5' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_public_shelf</div> <div class='testcase'>test_public_shelf</div>
</td> </td>
@ -1632,7 +1674,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt14.6' class='hiddenRow bg-success'> <tr id='pt15.6' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_rename_shelf</div> <div class='testcase'>test_rename_shelf</div>
</td> </td>
@ -1641,19 +1683,19 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='st14.7' class='none bg-warning'> <tr id='st15.7' class='none bg-warning'>
<td> <td>
<div class='testcase'>test_shelf_database_change</div> <div class='testcase'>test_shelf_database_change</div>
</td> </td>
<td colspan='6'> <td colspan='6'>
<div class="text-center"> <div class="text-center">
<a class="popup_link text-center" onfocus='blur()' onclick="showTestDetail('div_st14.7')">SKIP</a> <a class="popup_link text-center" onfocus='blur()' onclick="showTestDetail('div_st15.7')">SKIP</a>
</div> </div>
<!--css div popup start--> <!--css div popup start-->
<div id='div_st14.7' class="popup_window test_output" style="display:none;"> <div id='div_st15.7' class="popup_window test_output" style="display:none;">
<div class='close_button pull-right'> <div class='close_button pull-right'>
<button type="button" class="close" aria-label="Close" onfocus='this.blur();' <button type="button" class="close" aria-label="Close" onfocus='this.blur();'
onclick="document.getElementById('div_st14.7').style.display='none'"><span onclick="document.getElementById('div_st15.7').style.display='none'"><span
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
</div> </div>
<div class="text-left pull-left"> <div class="text-left pull-left">
@ -1667,7 +1709,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt14.8' class='hiddenRow bg-success'> <tr id='pt15.8' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_shelf_long_name</div> <div class='testcase'>test_shelf_long_name</div>
</td> </td>
@ -1685,13 +1727,13 @@ AssertionError: False is not true : logfile config value is not empty after rese
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center">1</td> <td class="text-center">1</td>
<td class="text-center"> <td class="text-center">
<a onclick="showClassDetail('c15', 7)">Detail</a> <a onclick="showClassDetail('c16', 7)">Detail</a>
</td> </td>
</tr> </tr>
<tr id='pt15.1' class='hiddenRow bg-success'> <tr id='pt16.1' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_check_update_nightly_errors</div> <div class='testcase'>test_check_update_nightly_errors</div>
</td> </td>
@ -1700,7 +1742,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt15.2' class='hiddenRow bg-success'> <tr id='pt16.2' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_check_update_nightly_request_errors</div> <div class='testcase'>test_check_update_nightly_request_errors</div>
</td> </td>
@ -1709,7 +1751,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt15.3' class='hiddenRow bg-success'> <tr id='pt16.3' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_check_update_stable_errors</div> <div class='testcase'>test_check_update_stable_errors</div>
</td> </td>
@ -1718,7 +1760,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt15.4' class='hiddenRow bg-success'> <tr id='pt16.4' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_check_update_stable_versions</div> <div class='testcase'>test_check_update_stable_versions</div>
</td> </td>
@ -1727,7 +1769,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt15.5' class='hiddenRow bg-success'> <tr id='pt16.5' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_perform_update</div> <div class='testcase'>test_perform_update</div>
</td> </td>
@ -1736,7 +1778,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt15.6' class='hiddenRow bg-success'> <tr id='pt16.6' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_perform_update_stable_errors</div> <div class='testcase'>test_perform_update_stable_errors</div>
</td> </td>
@ -1745,19 +1787,19 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='st15.7' class='none bg-warning'> <tr id='st16.7' class='none bg-warning'>
<td> <td>
<div class='testcase'>test_perform_update_timeout</div> <div class='testcase'>test_perform_update_timeout</div>
</td> </td>
<td colspan='6'> <td colspan='6'>
<div class="text-center"> <div class="text-center">
<a class="popup_link text-center" onfocus='blur()' onclick="showTestDetail('div_st15.7')">SKIP</a> <a class="popup_link text-center" onfocus='blur()' onclick="showTestDetail('div_st16.7')">SKIP</a>
</div> </div>
<!--css div popup start--> <!--css div popup start-->
<div id='div_st15.7' class="popup_window test_output" style="display:none;"> <div id='div_st16.7' class="popup_window test_output" style="display:none;">
<div class='close_button pull-right'> <div class='close_button pull-right'>
<button type="button" class="close" aria-label="Close" onfocus='this.blur();' <button type="button" class="close" aria-label="Close" onfocus='this.blur();'
onclick="document.getElementById('div_st15.7').style.display='none'"><span onclick="document.getElementById('div_st16.7').style.display='none'"><span
aria-hidden="true">&times;</span></button> aria-hidden="true">&times;</span></button>
</div> </div>
<div class="text-left pull-left"> <div class="text-left pull-left">
@ -1780,13 +1822,13 @@ AssertionError: False is not true : logfile config value is not empty after rese
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center"> <td class="text-center">
<a onclick="showClassDetail('c16', 17)">Detail</a> <a onclick="showClassDetail('c17', 17)">Detail</a>
</td> </td>
</tr> </tr>
<tr id='pt16.1' class='hiddenRow bg-success'> <tr id='pt17.1' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_allow_column_restriction</div> <div class='testcase'>test_allow_column_restriction</div>
</td> </td>
@ -1795,7 +1837,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.2' class='hiddenRow bg-success'> <tr id='pt17.2' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_allow_tag_restriction</div> <div class='testcase'>test_allow_tag_restriction</div>
</td> </td>
@ -1804,7 +1846,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.3' class='hiddenRow bg-success'> <tr id='pt17.3' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_author_user_template</div> <div class='testcase'>test_author_user_template</div>
</td> </td>
@ -1813,7 +1855,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.4' class='hiddenRow bg-success'> <tr id='pt17.4' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_best_user_template</div> <div class='testcase'>test_best_user_template</div>
</td> </td>
@ -1822,7 +1864,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.5' class='hiddenRow bg-success'> <tr id='pt17.5' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_category_user_template</div> <div class='testcase'>test_category_user_template</div>
</td> </td>
@ -1831,7 +1873,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.6' class='hiddenRow bg-success'> <tr id='pt17.6' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_deny_column_restriction</div> <div class='testcase'>test_deny_column_restriction</div>
</td> </td>
@ -1840,7 +1882,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.7' class='hiddenRow bg-success'> <tr id='pt17.7' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_deny_tag_restriction</div> <div class='testcase'>test_deny_tag_restriction</div>
</td> </td>
@ -1849,7 +1891,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.8' class='hiddenRow bg-success'> <tr id='pt17.8' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_detail_random_user_template</div> <div class='testcase'>test_detail_random_user_template</div>
</td> </td>
@ -1858,7 +1900,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.9' class='hiddenRow bg-success'> <tr id='pt17.9' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_hot_user_template</div> <div class='testcase'>test_hot_user_template</div>
</td> </td>
@ -1867,7 +1909,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.10' class='hiddenRow bg-success'> <tr id='pt17.10' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_language_user_template</div> <div class='testcase'>test_language_user_template</div>
</td> </td>
@ -1876,7 +1918,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.11' class='hiddenRow bg-success'> <tr id='pt17.11' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_limit_book_languages</div> <div class='testcase'>test_limit_book_languages</div>
</td> </td>
@ -1885,7 +1927,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.12' class='hiddenRow bg-success'> <tr id='pt17.12' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_publisher_user_template</div> <div class='testcase'>test_publisher_user_template</div>
</td> </td>
@ -1894,7 +1936,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.13' class='hiddenRow bg-success'> <tr id='pt17.13' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_random_user_template</div> <div class='testcase'>test_random_user_template</div>
</td> </td>
@ -1903,7 +1945,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.14' class='hiddenRow bg-success'> <tr id='pt17.14' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_read_user_template</div> <div class='testcase'>test_read_user_template</div>
</td> </td>
@ -1912,7 +1954,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.15' class='hiddenRow bg-success'> <tr id='pt17.15' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_recent_user_template</div> <div class='testcase'>test_recent_user_template</div>
</td> </td>
@ -1921,7 +1963,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.16' class='hiddenRow bg-success'> <tr id='pt17.16' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_series_user_template</div> <div class='testcase'>test_series_user_template</div>
</td> </td>
@ -1930,7 +1972,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt16.17' class='hiddenRow bg-success'> <tr id='pt17.17' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_ui_language_settings</div> <div class='testcase'>test_ui_language_settings</div>
</td> </td>
@ -1948,13 +1990,13 @@ AssertionError: False is not true : logfile config value is not empty after rese
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center">0</td> <td class="text-center">0</td>
<td class="text-center"> <td class="text-center">
<a onclick="showClassDetail('c17', 23)">Detail</a> <a onclick="showClassDetail('c18', 23)">Detail</a>
</td> </td>
</tr> </tr>
<tr id='pt17.1' class='hiddenRow bg-success'> <tr id='pt18.1' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_about</div> <div class='testcase'>test_about</div>
</td> </td>
@ -1963,7 +2005,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.2' class='hiddenRow bg-success'> <tr id='pt18.2' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_SMTP_Settings</div> <div class='testcase'>test_admin_SMTP_Settings</div>
</td> </td>
@ -1972,7 +2014,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.3' class='hiddenRow bg-success'> <tr id='pt18.3' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_add_user</div> <div class='testcase'>test_admin_add_user</div>
</td> </td>
@ -1981,7 +2023,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.4' class='hiddenRow bg-success'> <tr id='pt18.4' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_password</div> <div class='testcase'>test_admin_change_password</div>
</td> </td>
@ -1990,7 +2032,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.5' class='hiddenRow bg-success'> <tr id='pt18.5' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_authors</div> <div class='testcase'>test_admin_change_visibility_authors</div>
</td> </td>
@ -1999,7 +2041,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.6' class='hiddenRow bg-success'> <tr id='pt18.6' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_category</div> <div class='testcase'>test_admin_change_visibility_category</div>
</td> </td>
@ -2008,7 +2050,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.7' class='hiddenRow bg-success'> <tr id='pt18.7' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_file_formats</div> <div class='testcase'>test_admin_change_visibility_file_formats</div>
</td> </td>
@ -2017,7 +2059,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.8' class='hiddenRow bg-success'> <tr id='pt18.8' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_hot</div> <div class='testcase'>test_admin_change_visibility_hot</div>
</td> </td>
@ -2026,7 +2068,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.9' class='hiddenRow bg-success'> <tr id='pt18.9' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_language</div> <div class='testcase'>test_admin_change_visibility_language</div>
</td> </td>
@ -2035,7 +2077,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.10' class='hiddenRow bg-success'> <tr id='pt18.10' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_publisher</div> <div class='testcase'>test_admin_change_visibility_publisher</div>
</td> </td>
@ -2044,7 +2086,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.11' class='hiddenRow bg-success'> <tr id='pt18.11' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_rated</div> <div class='testcase'>test_admin_change_visibility_rated</div>
</td> </td>
@ -2053,7 +2095,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.12' class='hiddenRow bg-success'> <tr id='pt18.12' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_rating</div> <div class='testcase'>test_admin_change_visibility_rating</div>
</td> </td>
@ -2062,7 +2104,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.13' class='hiddenRow bg-success'> <tr id='pt18.13' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_read</div> <div class='testcase'>test_admin_change_visibility_read</div>
</td> </td>
@ -2071,7 +2113,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.14' class='hiddenRow bg-success'> <tr id='pt18.14' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_admin_change_visibility_series</div> <div class='testcase'>test_admin_change_visibility_series</div>
</td> </td>
@ -2080,7 +2122,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.15' class='hiddenRow bg-success'> <tr id='pt18.15' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_allow_columns</div> <div class='testcase'>test_allow_columns</div>
</td> </td>
@ -2089,7 +2131,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.16' class='hiddenRow bg-success'> <tr id='pt18.16' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_allow_tags</div> <div class='testcase'>test_allow_tags</div>
</td> </td>
@ -2098,7 +2140,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.17' class='hiddenRow bg-success'> <tr id='pt18.17' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_checked_logged_in</div> <div class='testcase'>test_checked_logged_in</div>
</td> </td>
@ -2107,7 +2149,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.18' class='hiddenRow bg-success'> <tr id='pt18.18' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_random_books_available</div> <div class='testcase'>test_random_books_available</div>
</td> </td>
@ -2116,7 +2158,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.19' class='hiddenRow bg-success'> <tr id='pt18.19' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_restrict_columns</div> <div class='testcase'>test_restrict_columns</div>
</td> </td>
@ -2125,7 +2167,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.20' class='hiddenRow bg-success'> <tr id='pt18.20' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_restrict_tags</div> <div class='testcase'>test_restrict_tags</div>
</td> </td>
@ -2134,7 +2176,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.21' class='hiddenRow bg-success'> <tr id='pt18.21' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_search_functions</div> <div class='testcase'>test_search_functions</div>
</td> </td>
@ -2143,7 +2185,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.22' class='hiddenRow bg-success'> <tr id='pt18.22' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_user_email_available</div> <div class='testcase'>test_user_email_available</div>
</td> </td>
@ -2152,7 +2194,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='pt17.23' class='hiddenRow bg-success'> <tr id='pt18.23' class='hiddenRow bg-success'>
<td> <td>
<div class='testcase'>test_user_visibility_sidebar</div> <div class='testcase'>test_user_visibility_sidebar</div>
</td> </td>
@ -2163,8 +2205,8 @@ AssertionError: False is not true : logfile config value is not empty after rese
<tr id='total_row' class="text-center bg-grey"> <tr id='total_row' class="text-center bg-grey">
<td>Total</td> <td>Total</td>
<td>183</td> <td>186</td>
<td>174</td> <td>177</td>
<td>2</td> <td>2</td>
<td>0</td> <td>0</td>
<td>7</td> <td>7</td>
@ -2307,6 +2349,30 @@ AssertionError: False is not true : logfile config value is not empty after rese
<td>test_kobo_sync</td> <td>test_kobo_sync</td>
</tr> </tr>
<tr>
<th>Flask-SimpleLDAP</th>
<td>1.4.0</td>
<td>test_ldap_login</td>
</tr>
<tr>
<th>python-ldap</th>
<td>3.2.0</td>
<td>test_ldap_login</td>
</tr>
<tr>
<th>Flask-Dance</th>
<td>3.0.0</td>
<td>test_OAuth_login</td>
</tr>
<tr>
<th>SQLAlchemy-Utils</th>
<td>0.36.3</td>
<td>test_OAuth_login</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@ -2315,7 +2381,7 @@ AssertionError: False is not true : logfile config value is not empty after rese
</div> </div>
<script> <script>
drawCircle(174, 2, 0, 7); drawCircle(177, 2, 0, 7);
</script> </script>
</div> </div>