offspot / cardshop Goto Github PK
View Code? Open in Web Editor NEWCreate Kiwix Hotspot microSD cards online
Home Page: https://cardshop.hotspot.kiwix.org
License: GNU General Public License v3.0
Create Kiwix Hotspot microSD cards online
Home Page: https://cardshop.hotspot.kiwix.org
License: GNU General Public License v3.0
I had about 20 small files on my list and then clicked "update" and got this error log:
´´´
Request Method: | GET |
---|---|
https://cardshop.hotspot.kiwix.org/configurations/2 | |
2.1.2 | |
KeyError | |
'tw' | |
./manager/templatetags/manager.py in , line 56 | |
/usr/local/bin/uwsgi | |
3.6.6 | |
['.', '', '/usr/local/lib/python36.zip', '/usr/local/lib/python3.6', '/usr/local/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/site-packages'] | |
Thu, 18 Oct 2018 13:16:53 +0000 |
Error during template rendering
In template /app/manager/templates/base.html, error at line 0
1 | {% load static %} |
---|
Environment:
Request Method: GET
Request URL: https://cardshop.hotspot.kiwix.org/configurations/2
Django Version: 2.1.2
Python Version: 3.6.6
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'manager']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Template error:
In template /app/manager/templates/base.html, error at line 0
tw
1 : {% load static %}
2 :
3 :
4 : <title>{% block title %}Kiwix Hotspot Cardshop{% endblock %}</title>
5 :
6 :
7 :
8 :
9 :
10 : <style type="text/css">
Traceback:
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
126. response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
124. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.6/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
21. return view_func(request, *args, **kwargs)
File "./manager/views/config.py" in edit_configuration
145. return render(request, "edit_configuration.html", context)
File "/usr/local/lib/python3.6/site-packages/django/shortcuts.py" in render
36. content = loader.render_to_string(template_name, context, request, using=using)
File "/usr/local/lib/python3.6/site-packages/django/template/loader.py" in render_to_string
62. return template.render(context, request)
File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py" in render
61. return self.template.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render
171. return self._render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in _render
163. return self.nodelist.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render
937. bit = node.render_annotated(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render_annotated
904. return self.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py" in render
150. return compiled_parent._render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in _render
163. return self.nodelist.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render
937. bit = node.render_annotated(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render_annotated
904. return self.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py" in render
62. result = block.nodelist.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render
937. bit = node.render_annotated(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render_annotated
904. return self.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/defaulttags.py" in render
161. values = self.sequence.resolve(context, ignore_failures=True)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in resolve
698. new_obj = func(obj, *arg_vals)
File "./manager/templatetags/manager.py" in as_packages
56. for pid in json.loads(value) or []
File "./manager/templatetags/manager.py" in
56. for pid in json.loads(value) or []
Exception Type: KeyError at /configurations/2
Exception Value: 'tw'
GET
No GET data
POST
No POST data
FILES
No FILES data
COOKIES Variable | Value |
---|---|
csrftoken | 'w5RJuWtIrb9hlt0ZUqziB9wB6yxAbzRJVuArYUut27vppMalhD5oIqYecQVW8zbj' |
sessionid | 'ql9k2shu89s2xkfxa5ya9x8qqehibrm2' |
messages | ('b84a683202cb5027259b83e56e44d5e8171051b5$[["__json_message",0,25,"Configuration ' 'Updated successfuly !"]]') |
META
Variable | Value |
---|---|
CONTENT_LENGTH | '' |
CONTENT_TYPE | '' |
CSRF_COOKIE | 'w5RJuWtIrb9hlt0ZUqziB9wB6yxAbzRJVuArYUut27vppMalhD5oIqYecQVW8zbj' |
CSRF_COOKIE_USED | True |
DOCUMENT_ROOT | '/etc/nginx/html' |
HTTP_ACCEPT | 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8' |
HTTP_ACCEPT_ENCODING | 'gzip, deflate, br' |
HTTP_ACCEPT_LANGUAGE | 'fr-CH,fr;q=0.9,en-CH;q=0.8,en;q=0.7,fr-FR;q=0.6,en-US;q=0.5' |
HTTP_CACHE_CONTROL | 'max-age=0' |
HTTP_CONNECTION | 'close' |
HTTP_COOKIE | ('csrftoken=w5RJuWtIrb9hlt0ZUqziB9wB6yxAbzRJVuArYUut27vppMalhD5oIqYecQVW8zbj; ' 'sessionid=ql9k2shu89s2xkfxa5ya9x8qqehibrm2; ' 'messages="b84a683202cb5027259b83e56e44d5e8171051b5$[[\"__json_message\"\0540\05425\054\"Configuration ' 'Updated successfuly !\"]]"') |
HTTP_DNT | '1' |
HTTP_HOST | 'cardshop.hotspot.kiwix.org' |
HTTP_REFERER | 'https://cardshop.hotspot.kiwix.org/configurations/2' |
HTTP_UPGRADE_INSECURE_REQUESTS | '1' |
HTTP_USER_AGENT | ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, ' 'like Gecko) Chrome/69.0.3497.100 Safari/537.36') |
HTTP_X_FORWARDED_FOR | '62.220.153.85' |
HTTP_X_FORWARDED_PORT | '443' |
HTTP_X_FORWARDED_PROTO | 'https' |
PATH_INFO | '/configurations/2' |
QUERY_STRING | '' |
REMOTE_ADDR | '192.168.18.27' |
REMOTE_PORT | '58058' |
REQUEST_METHOD | 'GET' |
REQUEST_SCHEME | 'http' |
REQUEST_URI | '/configurations/2' |
SCRIPT_NAME | '' |
SERVER_NAME | '' |
SERVER_PORT | '80' |
SERVER_PROTOCOL | 'HTTP/1.1' |
uwsgi.node | b'manager.frontend.cardshop.kiwixoffline.node.intern' |
uwsgi.version | b'2.0.17.1' |
wsgi.errors | <_io.TextIOWrapper name=2 mode='w' encoding='UTF-8'> |
wsgi.file_wrapper | '' |
wsgi.input | <uwsgi._Input object at 0x7effcec087e0> |
wsgi.multiprocess | True |
wsgi.multithread | False |
wsgi.run_once | False |
wsgi.url_scheme | 'https' |
wsgi.version | (1, 0) |
SETTINGS
Setting | Value |
---|---|
ABSOLUTE_URL_OVERRIDES | {} |
ADMINS | [] |
ADMIN_PASSWORD | '********************' |
ALLOWED_HOSTS | ['*'] |
APPEND_SLASH | True |
AUTHENTICATION_BACKENDS | ['django.contrib.auth.backends.ModelBackend'] |
AUTH_PASSWORD_VALIDATORS | '********************' |
AUTH_USER_MODEL | 'auth.User' |
BASE_DIR | '/app' |
CACHES | {'default': {'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/data/cache', 'OPTIONS': {'MAX_ENTRIES': 1000}, 'TIMEOUT': 86400}} |
CACHE_MIDDLEWARE_ALIAS | 'default' |
CACHE_MIDDLEWARE_KEY_PREFIX | '********************' |
CACHE_MIDDLEWARE_SECONDS | 600 |
CARDSHOP_API_URL | '********************' |
CONTENTS_FILE | '/app/contents.json' |
CSRF_COOKIE_AGE | 31449600 |
CSRF_COOKIE_DOMAIN | None |
CSRF_COOKIE_HTTPONLY | False |
CSRF_COOKIE_NAME | 'csrftoken' |
CSRF_COOKIE_PATH | '/' |
CSRF_COOKIE_SAMESITE | 'Lax' |
CSRF_COOKIE_SECURE | False |
CSRF_FAILURE_VIEW | 'django.views.csrf.csrf_failure' |
CSRF_HEADER_NAME | 'HTTP_X_CSRFTOKEN' |
CSRF_TRUSTED_ORIGINS | [] |
CSRF_USE_SESSIONS | False |
DATABASES | {'default': {'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'ENGINE': 'django.db.backends.sqlite3', 'HOST': '', 'NAME': '/data/manager.sqlite3', 'OPTIONS': {}, 'PASSWORD': '********************', 'PORT': '', 'TEST': {'CHARSET': None, 'COLLATION': None, 'MIRROR': None, 'NAME': None}, 'TIME_ZONE': None, 'USER': ''}} |
DATABASE_ROUTERS | [] |
DATA_DIR | '/data' |
DATA_UPLOAD_MAX_MEMORY_SIZE | 2621440 |
DATA_UPLOAD_MAX_NUMBER_FIELDS | 1000 |
DATETIME_FORMAT | 'N j, Y, P' |
DATETIME_INPUT_FORMATS | ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M:%S.%f', '%m/%d/%Y %H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M:%S.%f', '%m/%d/%y %H:%M', '%m/%d/%y'] |
DATE_FORMAT | 'N j, Y' |
DATE_INPUT_FORMATS | ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y', '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y', '%B %d, %Y', '%d %B %Y', '%d %B, %Y'] |
DEBUG | True |
DEBUG_PROPAGATE_EXCEPTIONS | False |
DECIMAL_SEPARATOR | '.' |
DEFAULT_CHARSET | 'utf-8' |
DEFAULT_CONTENT_TYPE | 'text/html' |
DEFAULT_EXCEPTION_REPORTER_FILTER | 'django.views.debug.SafeExceptionReporterFilter' |
DEFAULT_FILE_STORAGE | 'django.core.files.storage.FileSystemStorage' |
DEFAULT_FROM_EMAIL | 'webmaster@localhost' |
DEFAULT_INDEX_TABLESPACE | '' |
DEFAULT_TABLESPACE | '' |
DISALLOWED_USER_AGENTS | [] |
EMAIL_BACKEND | 'django.core.mail.backends.smtp.EmailBackend' |
EMAIL_HOST | 'localhost' |
EMAIL_HOST_PASSWORD | '********************' |
EMAIL_HOST_USER | '' |
EMAIL_PORT | 25 |
EMAIL_SSL_CERTFILE | None |
EMAIL_SSL_KEYFILE | '********************' |
EMAIL_SUBJECT_PREFIX | '[Django] ' |
EMAIL_TIMEOUT | None |
EMAIL_USE_LOCALTIME | False |
EMAIL_USE_SSL | False |
EMAIL_USE_TLS | False |
FILE_CHARSET | 'utf-8' |
FILE_UPLOAD_DIRECTORY_PERMISSIONS | None |
FILE_UPLOAD_HANDLERS | ['django.core.files.uploadhandler.MemoryFileUploadHandler', 'django.core.files.uploadhandler.TemporaryFileUploadHandler'] |
FILE_UPLOAD_MAX_MEMORY_SIZE | 2621440 |
FILE_UPLOAD_PERMISSIONS | None |
FILE_UPLOAD_TEMP_DIR | None |
FIRST_DAY_OF_WEEK | 0 |
FIXTURE_DIRS | [] |
FORCE_SCRIPT_NAME | None |
FORMAT_MODULE_PATH | None |
FORM_RENDERER | 'django.forms.renderers.DjangoTemplates' |
IGNORABLE_404_URLS | [] |
INSTALLED_APPS | ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'manager'] |
INTERNAL_IPS | [] |
LANGUAGES | [('af', 'Afrikaans'), ('ar', 'Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('dsb', 'Lower Sorbian'), ('el', 'Greek'), ('en', 'English'), ('en-au', 'Australian English'), ('en-gb', 'British English'), ('eo', 'Esperanto'), ('es', 'Spanish'), ('es-ar', 'Argentinian Spanish'), ('es-co', 'Colombian Spanish'), ('es-mx', 'Mexican Spanish'), ('es-ni', 'Nicaraguan Spanish'), ('es-ve', 'Venezuelan Spanish'), ('et', 'Estonian'), ('eu', 'Basque'), ('fa', 'Persian'), ('fi', 'Finnish'), ('fr', 'French'), ('fy', 'Frisian'), ('ga', 'Irish'), ('gd', 'Scottish Gaelic'), ('gl', 'Galician'), ('he', 'Hebrew'), ('hi', 'Hindi'), ('hr', 'Croatian'), ('hsb', 'Upper Sorbian'), ('hu', 'Hungarian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kab', 'Kabyle'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('my', 'Burmese'), ('nb', 'Norwegian Bokmål'), ('ne', 'Nepali'), ('nl', 'Dutch'), ('nn', 'Norwegian Nynorsk'), ('os', 'Ossetic'), ('pa', 'Punjabi'), ('pl', 'Polish'), ('pt', 'Portuguese'), ('pt-br', 'Brazilian Portuguese'), ('ro', 'Romanian'), ('ru', 'Russian'), ('sk', 'Slovak'), ('sl', 'Slovenian'), ('sq', 'Albanian'), ('sr', 'Serbian'), ('sr-latn', 'Serbian Latin'), ('sv', 'Swedish'), ('sw', 'Swahili'), ('ta', 'Tamil'), ('te', 'Telugu'), ('th', 'Thai'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')] |
LANGUAGES_BIDI | ['he', 'ar', 'fa', 'ur'] |
LANGUAGE_CODE | 'en-us' |
LANGUAGE_COOKIE_AGE | None |
LANGUAGE_COOKIE_DOMAIN | None |
LANGUAGE_COOKIE_NAME | 'django_language' |
LANGUAGE_COOKIE_PATH | '/' |
LOCALE_PATHS | [] |
LOGGING | {'disable_existing_loggers': False, 'handlers': {'console': {'class': 'logging.StreamHandler'}}, 'loggers': {'django': {'handlers': ['console'], 'level': 'INFO'}, 'manager': {'handlers': ['console'], 'level': 'DEBUG'}}, 'version': 1} |
LOGGING_CONFIG | 'logging.config.dictConfig' |
LOGIN_REDIRECT_URL | '/' |
LOGIN_URL | '/login' |
LOGOUT_REDIRECT_URL | '/' |
MANAGERS | [] |
MANAGER_API_KEY | '********************' |
MANAGER_API_USERNAME | '********************' |
MEDIA_ROOT | '/data/media' |
MEDIA_URL | '/media/' |
MESSAGE_STORAGE | 'django.contrib.messages.storage.fallback.FallbackStorage' |
MIDDLEWARE | ['django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware'] |
MIGRATION_MODULES | {} |
MIRROR | 'http://download.kiwix.org' |
MONTH_DAY_FORMAT | 'F j' |
NUMBER_GROUPING | 0 |
PASSWORD_HASHERS | '********************' |
PASSWORD_RESET_TIMEOUT_DAYS | '********************' |
PREPEND_WWW | False |
ROOT_URLCONF | 'manager.urls' |
SECRET_KEY | '********************' |
SECURE_BROWSER_XSS_FILTER | False |
SECURE_CONTENT_TYPE_NOSNIFF | False |
SECURE_HSTS_INCLUDE_SUBDOMAINS | False |
SECURE_HSTS_PRELOAD | False |
SECURE_HSTS_SECONDS | 0 |
SECURE_PROXY_SSL_HEADER | None |
SECURE_REDIRECT_EXEMPT | [] |
SECURE_SSL_HOST | None |
SECURE_SSL_REDIRECT | False |
SERVER_EMAIL | 'root@localhost' |
SESSION_CACHE_ALIAS | 'default' |
SESSION_COOKIE_AGE | 1209600 |
SESSION_COOKIE_DOMAIN | None |
SESSION_COOKIE_HTTPONLY | True |
SESSION_COOKIE_NAME | 'sessionid' |
SESSION_COOKIE_PATH | '/' |
SESSION_COOKIE_SAMESITE | 'Lax' |
SESSION_COOKIE_SECURE | False |
SESSION_ENGINE | 'django.contrib.sessions.backends.db' |
SESSION_EXPIRE_AT_BROWSER_CLOSE | False |
SESSION_FILE_PATH | None |
SESSION_SAVE_EVERY_REQUEST | False |
SESSION_SERIALIZER | 'django.contrib.sessions.serializers.JSONSerializer' |
SETTINGS_MODULE | 'manager.settings' |
SHORT_DATETIME_FORMAT | 'm/d/Y P' |
SHORT_DATE_FORMAT | 'm/d/Y' |
SIGNING_BACKEND | 'django.core.signing.TimestampSigner' |
SILENCED_SYSTEM_CHECKS | [] |
STATICFILES_DIRS | [] |
STATICFILES_FINDERS | ['django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder'] |
STATICFILES_STORAGE | 'django.contrib.staticfiles.storage.StaticFilesStorage' |
STATIC_ROOT | '/data/static' |
STATIC_URL | '/static/' |
SUPPORT_EMAIL | '[email protected]' |
TEMPLATES | [{'APP_DIRS': True, 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'OPTIONS': {'context_processors': ['django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages']}}] |
TEST_NON_SERIALIZED_APPS | [] |
TEST_RUNNER | 'django.test.runner.DiscoverRunner' |
THOUSAND_SEPARATOR | ',' |
TIME_FORMAT | 'P' |
TIME_INPUT_FORMATS | ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] |
TIME_ZONE | 'UTC' |
USE_I18N | True |
USE_L10N | True |
USE_THOUSAND_SEPARATOR | False |
USE_TZ | True |
USE_X_FORWARDED_HOST | False |
USE_X_FORWARDED_PORT | False |
WSGI_APPLICATION | 'manager.wsgi.application' |
X_FRAME_OPTIONS | 'SAMEORIGIN' |
YEAR_MONTH_FORMAT | 'F Y' |
Like any other node, it should be available only via SSL.
It is current "GiB". See https://en.wikipedia.org/wiki/Gigabyte
Related to #3 - I don't know if should be merged with this ticket or not, but basically I wasn't able to retrieve the page where my credits are listed (unless I logged out and then back in). So the top of the Config page, being where most people will want to start their journey, should have the current landing's wording.
Hi {{username}}!
Welcome to the Cardshop. Here you can freely import, design and export Kiwix Hotspot's presets (JSON files).
etc. etc.
Part of the text reads:
"Both option require you to pay a fee using a prepaid units system but obviously the virtual one is cheaper.
We don't need the superscript, or even the text in it - if people have access, they've paid the fee already and know what they got themselves into.
When pressing the update button on content or branding the user is sent back to the General tab. He/she should rather be directed to the logical next step
General > branding > content > adress > order
Added a local phone number without the country code and got a rather cryptic error message:
I suggest pre-filling the text field
country code + number
or+1 123 456 789
orFollowing discussion with @Popolechien, we might want the shop to offer image-creation service instead of physical SD-card.
Difference with the current workflow would be:
Challenges:
The landing page lists past orders (I suppose), and if there aren't any the most prominent item is the password change box. This is rather confusing.
The distinction is purely technical and has no bearing on end product.
In case users don't have a favicon and logo at hand, at least the space does not remain empty.
Also, the wording should be clear about it:
"This section allows you to replace some visual elements with your own branding. Currently the Kiwix logo will be used by default".
Kiwix logo can be found at: https://upload.wikimedia.org/wikipedia/commons/1/14/Kiwix_icon.svg
(based on user feedback)
Currently upon ordering a card a single email is sent to
These may or may not be the same individual.
Here are the current text and fields being used:
Dear [Recipient],
Your order of 1 x 64GB Download with the [configuration's name] configuration on it has been accepted by the system.
You will be notified when it is ready for download.
Should you have any question, your contact for this transaction is [Client] (copied).
Order ID [some number with link to order details on cardshop]
Size: Card size (as opposite to content size)
Quantity: _number of units ordered, or 1 if download
Units: nn.d
Destination: (e.g. Recipient's address)
Cardshop contact Client's email address
Status: created, date/hour
To avoid confusion, this should be split in two messages:
Client message: (putting changes in Bold
"Success!
Your order of 1 x 64GB Download with the [configuration's name] configuration has been accepted by the system.
[Recipient] will be notified, and will get another message when it is ready for download.
Order summary:
Order ID [some number with link to order details on cardshop]
Size: Card size
Quantity: number of units ordered, or 1 if download
Unit cost: nn U (<- note: removed the decimal count in the number of units)
Destination: (e.g. Recipient's address)
You have XYZ units left on your account."
Recipient message
"Good news!
Client has placed an order for you on the Kiwix Cardshop. You will receive another message when the content is ready for shipping or download."
Emails are essential to the scheduler as it is though emails that it communicates with its users: recipients, clients (person who orders on the website) and writer operators.
scheduler uses SMTP to connect to a mailbox [email protected]
to send emails.
While this works locally, it doesn't work on Sloppy dues to Spam mitigation strategies (at Gandi but also at Gmail and probably any Email provider).
To circumvent this, I have added support for mailgun HTTP API as an alternative (used if MAILGUN_API_KEY
env is specified) to SMTP.
Mailgun offers 10,000 emails/month with their free package (see pricing) and has a simple API. It's a dedicated service which handles emails correctly. Instructions to verify domains are easy and they have incoming email support (webhooks).
Amazon offers a similar service AWS SES but it seems the free 65K emails/months are only for apps hosted on AWS.
Way forward:
cardshop.hotspot.kiwix.org
domain.See #43 - but not a priority at this stage as this is probably going to be an edge case.
Use case: I generated a list, then removed some items. When the mouse hovers on the +/- symbol then the file name appears. In this case I removed bangla content and added english, but the mousehover text box did not clear properly (even when clicking randomly around the window).
As a quickfix, I would probably no show these text boxes in the first place.
Right now if I saved and made a mistake in my addressing I need to delete and re-create the entry. Simply add an edit
button next to the delete
one in the list of addresses.
The "Link validity" is not needed (it sounds rather greedy to triple the cost when tripling duration). Let's set a default to seven days (or 10, whatever), have it notified in the delivery email, and be done with it.
The Quantity dropdown could be replaced by a text field : it's easier to type 5 than dropdown>scroll down > select.
Pressing the "delete" button next to an address does not work.
Contact should be hotspot at kiwix.org
- I don't think a personal address makes much sense (roles and responsabilities evolve, people go on vacations) and it's easier to track and manage tickets like this on Freshdesk.
The current structure is 1Gb = 1 Unit. Hardware prices, however, are not linear: a quick benchmark on Amazon gave the following prices: 8 / 10 / 15 / 30 / 50 / 70 USD for 16/ 32/ 64/ 128/ 200 and 256 Gb, respectively, ie an 9x ratio between the smallest and biggest ones.
Prices will evolve but hopefully the ratio will remain within those boundaries. I would therefore attribute 2 Units to 16Gb cards (and below; if someone for some reason orders an empty-ish card, we still need to cover handling), then 3, 4, 8, 13 and 18 units.
Since this is the last step, Save is an option, but not the most likely one: users will probably want to close the deal and finalize their order. There should therefore be at least a "Next" button but most likely something more of a call to action, like "Order card!/"Place order"/"Confirm delivery address"
Also the Save/Next button(s) should be located under the Selected package list: if I'm looking at Afar then it's fine and not too far, but in English I'd have to scroll quite a bit before finding it.
Someone who only wants a download link has no reason to send this info.
Probably related to #12 : when adding which ever stackexchange package to my selected contents, it does not move from the "available" to "selected" list, yet its weight is added to that of the card.
Already mentioned in #37: basically the update button could work as "Next" and take the client from
General to Branding to Content to Address to Order (meaning that order and address should not only be as top right menu items but also as part of the Configuration tabs.
Alternatively, if for some reason this is too complex to implement, add a "Order!" button below "update configuration" on the Content tab.
When writing their address users have had to type pretty much everything already, so they can type their home country as well - also some browser will fill that field automatically from previous forms, it'll always be faster than looking for a specific country in a 200+ list.
For security reasons. HTTP should be forwared to HTTPS.
If addresses or preexisting orders have been made, then the current display is fine.
Currently not sure it's the image I want.
Also, is there a suggested size (e.g. square), or minimum (50*50px)?
Question: do we really need a favicon? People might get confused as to what this is, and honestly it's not that important on a tab (case in point: the cardshop does not have a favicon). I'm not asking to remove it, but I wouldn't see a drawback to branding all tabs with a default Kiwix favicon.
How many use cases do we plan of people adding their own CSS? If the answer is "not many", I'd probably remove that option for the time being or, better, only have it appear on Admin accounts along with the favicon option (my understanding is that there will be admin accounts like mine and user accounts for FO end-users)
Currently everyone can see everyone else's card creations, this is confusing and will quickly create clutter.
The version column indicates the date at which the zim file was generated: I see no added value to this info as:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.