V1.31 exercise_type clone, evaluation inline

This commit is contained in:
Tibor Bossanyi (Freelancer) 2021-10-19 08:23:52 +02:00
parent ae805ffcf5
commit 2a4731dc29
26 changed files with 295 additions and 100 deletions

View File

@ -5,7 +5,7 @@ from .exercise_plan_template import ExercisePlanTemplateAdmin, ExercisePlanTempl
from .product import ProductAdmin from .product import ProductAdmin
from .exercise_device import ExerciseDeviceAdmin from .exercise_device import ExerciseDeviceAdmin
from .tutorial import TutorialAdmin from .tutorial import TutorialAdmin
from .evaluation import EvaluationAdmin, EvaluationAttributeAdmin from .evaluation import EvaluationAdmin
from .exercise_plan import ExercisePlanAdmin from .exercise_plan import ExercisePlanAdmin
from .description import DescriptionAdmin from .description import DescriptionAdmin
from .training_plan import TrainingPlanAdmin, TrainingPlanDetailAdmin from .training_plan import TrainingPlanAdmin, TrainingPlanDetailAdmin

View File

@ -5,5 +5,5 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<p>Controlling</p> <p>Controlling2</p>
{% endblock %} {% endblock %}

View File

@ -25,5 +25,5 @@ class ControllingAdmin(admin.ModelAdmin):
] ]
admin.site.register(Controlling, ControllingAdmin) #admin.site.register(Controlling, ControllingAdmin)
admin.autodiscover() #admin.autodiscover()

View File

@ -19,5 +19,5 @@ class DescriptionAdmin(admin.ModelAdmin):
] ]
admin.site.register(Description, DescriptionAdmin) #admin.site.register(Description, DescriptionAdmin)
admin.autodiscover() #admin.autodiscover()

View File

@ -1,32 +1,42 @@
from adminsortable2.admin import SortableInlineAdminMixin
from django.contrib import admin from django.contrib import admin
#from .inline_select_action import BaseInlineSelectActionsMixin
from inline_actions.admin import InlineActionsMixin, InlineActionsModelAdminMixin
from ..models.evaluation import EvaluationAttribute, Evaluation from ..models.evaluation import EvaluationAttribute, Evaluation
from django.utils.translation import ugettext_lazy as _
from django.contrib import messages
class EvaluationAdmin(admin.ModelAdmin): class EvaluationAttributeInline(InlineActionsMixin, SortableInlineAdminMixin, admin.TabularInline):
model = EvaluationAttribute
extra = 0
list_display = (
'sort', 'evaluation_attr_id', 'name', 'sex', 'age_min', 'age_max', 'value_min', 'value_max', 'evaluation_text')
list_editable = ('sort', 'name', 'sex', 'age_min', 'age_max', 'value_min', 'value_max', 'evaluation_text')
list_display_links = ('sort', )
ordering = ('sort',)
inline_actions = ('clone_eval',)
def clone_eval(self, request, obj, parent_obj=None):
print("cloning {obj}")
obj.pk = None
obj.name = obj.name + "_copy"
obj.save()
messages.info(request, f'{obj} has been cloned')
clone_eval.short_description = _("Clone the selected evaluation")
class EvaluationAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
list_display = ('evaluation_id', 'name', 'get_exercise_type') list_display = ('evaluation_id', 'name', 'get_exercise_type')
def get_exercise_type(self, obj): def get_exercise_type(self, obj):
return obj.exercise_type.name return obj.exercise_type.name
inlines = [
class EvaluationAttributeAdmin(admin.ModelAdmin): EvaluationAttributeInline
list_display = ( ]
'evaluation_attr_id', 'name', 'sex', 'age_min', 'age_max', 'value_min', 'value_max', 'evaluation_text')
list_editable = ('name', 'sex', 'age_min', 'age_max', 'value_min', 'value_max', 'evaluation_text')
list_filter = ('evaluation',)
def copy_attributes(self, request, queryset):
for objectAttr in reversed(queryset):
objectAttr.pk = None
objectAttr.name = objectAttr.name + "_copy"
objectAttr.save()
copy_attributes.short_description = "Clone the selected attribute"
actions = [copy_attributes]
admin.site.register(Evaluation, EvaluationAdmin) admin.site.register(Evaluation, EvaluationAdmin)
admin.site.register(EvaluationAttribute, EvaluationAttributeAdmin)
admin.autodiscover() admin.autodiscover()

View File

@ -50,6 +50,15 @@ class ExerciseTypeAdmin(admin.ModelAdmin):
list_display = ('exercise_type_id', 'name_colored', 'active', 'base', 'buddy_warning', 'is_description', 'is_desc_hu', 'alternatives') list_display = ('exercise_type_id', 'name_colored', 'active', 'base', 'buddy_warning', 'is_description', 'is_desc_hu', 'alternatives')
search_fields = ['name', 'exercisetypetranslation__name'] search_fields = ['name', 'exercisetypetranslation__name']
fields = ('name', 'description', 'unit', 'unit_quantity', 'unit_quantity_unit', 'active', 'base', 'buddy_warning') fields = ('name', 'description', 'unit', 'unit_quantity', 'unit_quantity_unit', 'active', 'base', 'buddy_warning')
list_filter = ('active','base', 'buddy_warning')
actions = ('clone',)
@admin.action(description=_('Clone exercise type'))
def clone(modeladmin, request, queryset):
for qs in queryset:
qs.pk = None
qs.name = qs.name + "_copy"
qs.save()
def name_colored(self, obj): def name_colored(self, obj):
if obj.active: if obj.active:

View File

@ -108,7 +108,7 @@ class BaseInlineSelectActionsMixin:
) )
) )
print("Buttons " + str(buttons)) #print("Buttons " + str(buttons))
return mark_safe( return mark_safe(
'<div class="submit_row inline_select_actions">{}</div>'.format(''.join(buttons)) '<div class="submit_row inline_select_actions">{}</div>'.format(''.join(buttons))
) )

View File

@ -7,5 +7,5 @@ class ProductAdmin(admin.ModelAdmin):
list_display = ('product_id', 'name', 'type') list_display = ('product_id', 'name', 'type')
admin.site.register(Product, ProductAdmin) #admin.site.register(Product, ProductAdmin)
admin.autodiscover() #admin.autodiscover()

View File

@ -18,7 +18,7 @@ class TrainingPlanDetailInline(BaseInlineSelectActionsMixin, SortableInlineAdmin
list_display_links = ('sort', ) list_display_links = ('sort', )
ordering = ('sort',) ordering = ('sort',)
inline_select_actions = ['copy_attributes',] inline_select_actions = ['clone',]
def repeat_max(self, obj): def repeat_max(self, obj):
if obj.repeat_max: if obj.repeat_max:
@ -47,7 +47,7 @@ class TrainingPlanDetailInline(BaseInlineSelectActionsMixin, SortableInlineAdmin
return actions return actions
@admin.action(description='clone') @admin.action(description='clone')
def copy_attributes(self, request, obj, parent_obj=None): def clone(self, request, obj, parent_obj=None):
name = str(request.queryset[0].training_plan) name = str(request.queryset[0].training_plan)
details = TrainingPlanDetail.objects.filter(training_plan__name=name).order_by('sort') details = TrainingPlanDetail.objects.filter(training_plan__name=name).order_by('sort')
@ -59,7 +59,7 @@ class TrainingPlanDetailInline(BaseInlineSelectActionsMixin, SortableInlineAdmin
objectAttr.save() objectAttr.save()
new_sort = new_sort + 1 new_sort = new_sort + 1
copy_attributes.short_description = _("Clone the selected Training Plan Detail") clone.short_description = _("Clone the selected Training Plan Detail")
def select_max_repeat(self, request, queryset): def select_max_repeat(self, request, queryset):
for obj in queryset: for obj in queryset:

View File

@ -93,6 +93,6 @@ class TutorialAdmin(admin.ModelAdmin):
fields = ('name',) fields = ('name',)
admin.site.register(Tutorial, TutorialAdmin) #admin.site.register(Tutorial, TutorialAdmin)
admin.site.register(TutorialSteps, TutorialStepsAdmin) #admin.site.register(TutorialSteps, TutorialStepsAdmin)
admin.autodiscover() #admin.autodiscover()

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-26 11:21+0200\n" "POT-Creation-Date: 2021-10-17 10:52+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -22,14 +22,17 @@ msgstr ""
#: .\aitrainer_backoffice\admin\exercise_device.py:32 #: .\aitrainer_backoffice\admin\exercise_device.py:32
#: .\aitrainer_backoffice\admin\exercise_type.py:27 #: .\aitrainer_backoffice\admin\exercise_type.py:27
#: .\aitrainer_backoffice\admin\exercisetree.py:41 #: .\aitrainer_backoffice\admin\exercisetree.py:41
#: .\aitrainer_backoffice\admin\notification.py:21
msgid "Image Preview" msgid "Image Preview"
msgstr "Kép előnézet" msgstr "Kép előnézet"
#: .\aitrainer_backoffice\admin\evaluation.py:29
msgid "Clone the selected evaluation"
msgstr "Kiértékelés klónozása"
#: .\aitrainer_backoffice\admin\inline_select_action.py:116 #: .\aitrainer_backoffice\admin\inline_select_action.py:116
#, fuzzy
#| msgid "Descriptions"
msgid "Actions" msgid "Actions"
msgstr "Leírás" msgstr "Akciók"
#: .\aitrainer_backoffice\admin\training_plan.py:30 #: .\aitrainer_backoffice\admin\training_plan.py:30
#: .\aitrainer_backoffice\admin\training_plan.py:159 #: .\aitrainer_backoffice\admin\training_plan.py:159
@ -43,10 +46,8 @@ msgstr "Ismétlés: -1, HA MAX ismétlés"
#: .\aitrainer_backoffice\admin\training_plan.py:62 #: .\aitrainer_backoffice\admin\training_plan.py:62
#: .\aitrainer_backoffice\admin\training_plan.py:185 #: .\aitrainer_backoffice\admin\training_plan.py:185
#, fuzzy
#| msgid "Training Plan Detail"
msgid "Clone the selected Training Plan Detail" msgid "Clone the selected Training Plan Detail"
msgstr "Edzésprogram részlet" msgstr "Edzésprogram klónozása"
#: .\aitrainer_backoffice\admin\training_plan.py:69 #: .\aitrainer_backoffice\admin\training_plan.py:69
#: .\aitrainer_backoffice\admin\training_plan.py:192 #: .\aitrainer_backoffice\admin\training_plan.py:192
@ -63,11 +64,10 @@ msgid "text_key"
msgstr "Szöveg kulcs" msgstr "Szöveg kulcs"
#: .\aitrainer_backoffice\models\app_text.py:11 #: .\aitrainer_backoffice\models\app_text.py:11
msgid "App képernyőkép" msgid "App Screenshot"
msgstr "" msgstr "Képernyőkép"
#: .\aitrainer_backoffice\models\app_text.py:12 #: .\aitrainer_backoffice\models\app_text.py:12
#| msgid "Translations"
msgid "Checked, Translation is OK" msgid "Checked, Translation is OK"
msgstr "Fordítás rendben, ellenőrizve" msgstr "Fordítás rendben, ellenőrizve"
@ -88,7 +88,7 @@ msgstr "App Fordítások"
#: .\aitrainer_backoffice\models\exercisetree.py:36 #: .\aitrainer_backoffice\models\exercisetree.py:36
#: .\aitrainer_backoffice\models\faq.py:34 #: .\aitrainer_backoffice\models\faq.py:34
#: .\aitrainer_backoffice\models\property.py:29 #: .\aitrainer_backoffice\models\property.py:29
#: .\aitrainer_backoffice\models\sports.py:31 #: .\aitrainer_backoffice\models\sports.py:29
#: .\aitrainer_backoffice\models\training_plan.py:58 #: .\aitrainer_backoffice\models\training_plan.py:58
#: .\aitrainer_backoffice\models\training_plan_day.py:31 #: .\aitrainer_backoffice\models\training_plan_day.py:31
#: .\aitrainer_backoffice\models\tutorial.py:45 #: .\aitrainer_backoffice\models\tutorial.py:45
@ -104,20 +104,21 @@ msgstr "Fordítás"
#: .\aitrainer_backoffice\models\exercisetree.py:37 #: .\aitrainer_backoffice\models\exercisetree.py:37
#: .\aitrainer_backoffice\models\faq.py:35 #: .\aitrainer_backoffice\models\faq.py:35
#: .\aitrainer_backoffice\models\property.py:30 #: .\aitrainer_backoffice\models\property.py:30
#: .\aitrainer_backoffice\models\sports.py:32 #: .\aitrainer_backoffice\models\sports.py:30
#: .\aitrainer_backoffice\models\training_plan.py:59 #: .\aitrainer_backoffice\models\training_plan.py:59
#: .\aitrainer_backoffice\models\training_plan_day.py:32 #: .\aitrainer_backoffice\models\training_plan_day.py:32
#: .\aitrainer_backoffice\models\tutorial.py:46 #: .\aitrainer_backoffice\models\tutorial.py:46
msgid "Translations" msgid "Translations"
msgstr "Fordítások" msgstr "Fordítások"
#: .\aitrainer_backoffice\models\customer.py:9
#: .\aitrainer_backoffice\models\description.py:11 #: .\aitrainer_backoffice\models\description.py:11
#: .\aitrainer_backoffice\models\evaluation.py:41 #: .\aitrainer_backoffice\models\evaluation.py:41
#: .\aitrainer_backoffice\models\faq.py:11 #: .\aitrainer_backoffice\models\faq.py:11
#: .\aitrainer_backoffice\models\faq.py:29 #: .\aitrainer_backoffice\models\faq.py:29
#: .\aitrainer_backoffice\models\split_tests.py:7 #: .\aitrainer_backoffice\models\split_tests.py:7
#: .\aitrainer_backoffice\models\sports.py:11 #: .\aitrainer_backoffice\models\sports.py:9
#: .\aitrainer_backoffice\models\sports.py:27 #: .\aitrainer_backoffice\models\sports.py:25
#: .\aitrainer_backoffice\models\training_plan.py:14 #: .\aitrainer_backoffice\models\training_plan.py:14
#: .\aitrainer_backoffice\models\training_plan_day.py:11 #: .\aitrainer_backoffice\models\training_plan_day.py:11
#: .\aitrainer_backoffice\models\training_plan_day.py:27 #: .\aitrainer_backoffice\models\training_plan_day.py:27
@ -125,6 +126,21 @@ msgstr "Fordítások"
msgid "name" msgid "name"
msgstr "Név" msgstr "Név"
#: .\aitrainer_backoffice\models\customer.py:10
#| msgid "name"
msgid "firstname"
msgstr "Keresztnév"
#: .\aitrainer_backoffice\models\customer.py:28
#| msgid "Customer Property"
msgid "Customer"
msgstr "Ügyfél"
#: .\aitrainer_backoffice\models\customer.py:29
#| msgid "Customer Properties"
msgid "Customers"
msgstr "Ügyfelek"
#: .\aitrainer_backoffice\models\description.py:19 #: .\aitrainer_backoffice\models\description.py:19
msgid "Description" msgid "Description"
msgstr "Leírás" msgstr "Leírás"
@ -147,7 +163,7 @@ msgstr "Kiértékelés"
#: .\aitrainer_backoffice\models\evaluation.py:17 #: .\aitrainer_backoffice\models\evaluation.py:17
msgid "Evaluations" msgid "Evaluations"
msgstr "Kiértékelés Csoport" msgstr "Kiértékelések"
#: .\aitrainer_backoffice\models\evaluation.py:40 #: .\aitrainer_backoffice\models\evaluation.py:40
msgid "evaluation_foreign" msgid "evaluation_foreign"
@ -181,13 +197,13 @@ msgstr "Osztályozás"
msgid "suggestion" msgid "suggestion"
msgstr "Javaslat" msgstr "Javaslat"
#: .\aitrainer_backoffice\models\evaluation.py:54
msgid "Evaluation Table"
msgstr "Kiértékelés tábla"
#: .\aitrainer_backoffice\models\evaluation.py:55 #: .\aitrainer_backoffice\models\evaluation.py:55
msgid "Evaluation Table"
msgstr "Kiértékelés"
#: .\aitrainer_backoffice\models\evaluation.py:56
msgid "Evaluation Tables" msgid "Evaluation Tables"
msgstr "Kiértékelés táblák" msgstr "Kiértékelések"
#: .\aitrainer_backoffice\models\exercise_device.py:18 #: .\aitrainer_backoffice\models\exercise_device.py:18
#: .\aitrainer_backoffice\models\exercise_type.py:87 #: .\aitrainer_backoffice\models\exercise_type.py:87
@ -301,6 +317,15 @@ msgstr "GYÍK"
msgid "FAQs" msgid "FAQs"
msgstr "GYÍK" msgstr "GYÍK"
#: .\aitrainer_backoffice\models\notification.py:20
msgid "Notification"
msgstr ""
#: .\aitrainer_backoffice\models\notification.py:21
#| msgid "Descriptions"
msgid "Notifications"
msgstr ""
#: .\aitrainer_backoffice\models\product.py:24 #: .\aitrainer_backoffice\models\product.py:24
msgid "Product" msgid "Product"
msgstr "Termék" msgstr "Termék"
@ -333,11 +358,11 @@ msgstr "A/B Teszt"
msgid "A/B Tests" msgid "A/B Tests"
msgstr "A/B Tesztek" msgstr "A/B Tesztek"
#: .\aitrainer_backoffice\models\sports.py:15 #: .\aitrainer_backoffice\models\sports.py:13
msgid "Sport" msgid "Sport"
msgstr "" msgstr ""
#: .\aitrainer_backoffice\models\sports.py:16 #: .\aitrainer_backoffice\models\sports.py:14
msgid "Sports" msgid "Sports"
msgstr "" msgstr ""
@ -358,13 +383,11 @@ msgid "Training Plan Details"
msgstr "Edzésprogram részletek" msgstr "Edzésprogram részletek"
#: .\aitrainer_backoffice\models\training_plan_day.py:15 #: .\aitrainer_backoffice\models\training_plan_day.py:15
#, fuzzy
#| msgid "Training Plan" #| msgid "Training Plan"
msgid "Training Day" msgid "Training Day"
msgstr "Edzésnap" msgstr "Edzésnap"
#: .\aitrainer_backoffice\models\training_plan_day.py:16 #: .\aitrainer_backoffice\models\training_plan_day.py:16
#, fuzzy
#| msgid "Training Plans" #| msgid "Training Plans"
msgid "Training Days" msgid "Training Days"
msgstr "Edzésnapok" msgstr "Edzésnapok"

View File

@ -8,7 +8,7 @@ class AppText(models.Model):
text_id = models.AutoField(primary_key=True) text_id = models.AutoField(primary_key=True)
text_key = models.TextField(max_length=255, help_text='Do not edit this! It is the key in the mobile app', text_key = models.TextField(max_length=255, help_text='Do not edit this! It is the key in the mobile app',
verbose_name=_("text_key")) verbose_name=_("text_key"))
screenshot_url = models.ImageField(upload_to='images/', help_text='The menu image size is 1366x768', blank=True,verbose_name=_("App képernyőkép") ) screenshot_url = models.ImageField(upload_to='images/', help_text='The menu image size is 1366x768', blank=True,verbose_name=_("App Screenshot") )
checked = models.BooleanField(blank=True, verbose_name=_("Checked, Translation is OK")) checked = models.BooleanField(blank=True, verbose_name=_("Checked, Translation is OK"))
class Meta: class Meta:

View File

@ -15,6 +15,7 @@ class Customer(models.Model):
date_add = models.DateField() date_add = models.DateField()
synced_date = models.DateTimeField(blank=True,null=True) synced_date = models.DateTimeField(blank=True,null=True)
firebase_reg_token = models.CharField(max_length=255, blank=True, null=True) firebase_reg_token = models.CharField(max_length=255, blank=True, null=True)
lang = models.CharField(max_length=5, blank=True, null=True)
def has_add_permission(self, request): def has_add_permission(self, request):
return False return False

View File

@ -48,11 +48,13 @@ class EvaluationAttribute(models.Model):
verbose_name=_("evaluation_text")) verbose_name=_("evaluation_text"))
suggestion = models.TextField(max_length=1000, blank=True, null=True, help_text="English suggestion here", suggestion = models.TextField(max_length=1000, blank=True, null=True, help_text="English suggestion here",
verbose_name=_("suggestion")) verbose_name=_("suggestion"))
sort = models.IntegerField()
class Meta: class Meta:
db_table = 'evaluation_attribute' db_table = 'evaluation_attribute'
verbose_name = _("Evaluation Table") verbose_name = _("Evaluation Table")
verbose_name_plural = _("Evaluation Tables") verbose_name_plural = _("Evaluation Tables")
ordering = ['sort']
def __str__(self): def __str__(self):
return self.name return self.name

View File

@ -1,7 +1,7 @@
import os import os
from firebase_admin import initialize_app from firebase_admin import initialize_app
BACKOFFICE_VERSION = "1.30" BACKOFFICE_VERSION = "1.31"
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -9,16 +9,18 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale')] LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale')]
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ['DJANGO_KEY'] SECRET_KEY = "lkasdjhklj84ujn3jk4nr5j43njk" #os.environ['DJANGO_KEY']
GOOGLE_APPLICATION_CREDENTIALS="/aitrainer_backoffice/aitrainer_backoffice/aitrainer_backoffice/asset/aitrainer-firebase-adminsdk.json"
os.environ["WORKOUTTEST_SETTING"] = "DEPLOY" os.environ["WORKOUTTEST_SETTING"] = "DEPLOY"
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False DEBUG = False
ALLOWED_HOSTS = ['62.171.188.119', "admin.aitrainer.app"] ALLOWED_HOSTS = ['62.171.188.119', "admin.aitrainer.app"]
env = os.environ['GOOGLE_APPLICATION_CREDENTIALS'] #env = os.environ['GOOGLE_APPLICATION_CREDENTIALS']
FIREBASE_APP = initialize_app() FIREBASE_APP = initialize_app()
DEFAULT_AUTO_FIELD='django.db.models.AutoField' DEFAULT_AUTO_FIELD='django.db.models.AutoField'

View File

@ -1,7 +1,7 @@
import os import os
from firebase_admin import initialize_app from firebase_admin import initialize_app
BACKOFFICE_VERSION = "1.30" BACKOFFICE_VERSION = "1.31"
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

View File

@ -1,7 +1,7 @@
import os import os
from firebase_admin import initialize_app from firebase_admin import initialize_app
BACKOFFICE_VERSION = "1.30" BACKOFFICE_VERSION = "1.31"
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

View File

@ -0,0 +1,30 @@
{% load i18n admin_urls static %}
<div class="js-inline-admin-formset inline-group"
id="{{ inline_admin_formset.formset.prefix }}-group"
data-inline-type="stacked"
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
<fieldset class="module {{ inline_admin_formset.classes }}">
{% if inline_admin_formset.formset.max_num == 1 %}
<h2>{{ inline_admin_formset.opts.verbose_name|capfirst }}</h2>
{% else %}
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
{% endif %}
{{ inline_admin_formset.formset.management_form }}
{{ inline_admin_formset.formset.non_form_errors }}
<h3>-- Actions Inline -- </h3>
{% for inline_admin_form in inline_admin_formset %}<div class="inline-related{% if inline_admin_form.original or inline_admin_form.show_url %} has_original{% endif %}{% if forloop.last and inline_admin_formset.has_add_permission %} empty-form last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<h3><b>{{ inline_admin_formset.opts.verbose_name|capfirst }}:</b> <span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} <a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="{% if inline_admin_formset.has_change_permission %}inlinechangelink{% else %}inlineviewlink{% endif %}">{% if inline_admin_formset.has_change_permission %}{% translate "Change" %}{% else %}{% translate "View" %}{% endif %}</a>{% endif %}
{% else %}#{{ forloop.counter }}{% endif %}</span>
{% if inline_admin_form.show_url %}<a href="{{ inline_admin_form.absolute_url }}">{% translate "View on site" %}</a>{% endif %}
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
</h3>
{% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %}
{% for fieldset in inline_admin_form %}
{% include "admin/includes/fieldset.html" %}
{% endfor %}
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %}
</div>{% endfor %}
</fieldset>
</div>

View File

@ -0,0 +1,84 @@
{% load i18n admin_urls static admin_modify %}
<div class="inline-group sortable" id="{{ inline_admin_formset.formset.prefix }}-group">
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
{{ inline_admin_formset.formset.management_form }}
<fieldset class="module {{ inline_admin_formset.classes }}">
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
{{ inline_admin_formset.formset.non_form_errors }}
<h3>-- Actions Inline -- </h3>
<p>{{ inline_action_form|default:"" }}</p>
<table>
<thead><tr><th>{% trans "Sort" %}</th>
{% for field in inline_admin_formset.fields %}
{% if not field.widget.is_hidden %}
<th{% if forloop.first %} colspan="2"{% endif %}{% if field.required %} class="required"{% endif %}>{{ field.label|capfirst }}
{% if field.help_text %}&nbsp;<img src="{% static "admin/img/icon-unknown.svg" %}" class="help help-tooltip" width="10" height="10" alt="({{ field.help_text|striptags }})" title="{{ field.help_text|striptags }}" />{% endif %}
</th>
{% endif %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}<th>{% trans "Delete?" %}</th>{% endif %}
</tr></thead>
<tbody>
{% for inline_admin_form in inline_admin_formset %}
{% if inline_admin_form.form.non_field_errors %}
<tr><td colspan="{{ inline_admin_form|cell_count|add:1 }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="form-row {% cycle "row1" "row2" %} {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last and inline_admin_formset.has_add_permission %} empty-form{% endif %}"
id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<td class="drag">&nbsp;</td>
<td class="original">
{% if inline_admin_form.original or inline_admin_form.show_url %}<p>
{% if inline_admin_form.original %}
{{ inline_admin_form.original }}
{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="inlinechangelink">{% trans "Change" %}</a>{% endif %}
{% endif %}
{% if inline_admin_form.show_url %}<a href="{{ inline_admin_form.absolute_url }}">{% trans "View on site" %}</a>{% endif %}
</p>{% endif %}
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
{% spaceless %}
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if field.field.is_hidden %} {{ field.field }} {% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endspaceless %}
</td>
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if not field.field.is_hidden %}
<td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}>
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
{{ field.field.errors.as_ul }}
{{ field.field }}
{% endif %}
</td>
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}
<td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
</div>
</div>
<script type="application/json" class="inline-tabular-config">
{
"prefix": "{{ inline_admin_formset.formset.prefix|escapejs }}",
"addText": "{% filter escapejs %}{% blocktrans with inline_admin_formset.opts.verbose_name|capfirst as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}{% endfilter %}",
"deleteText": "{% filter escapejs %}{% trans 'Remove' %}{% endfilter %}"
}
</script>
<div class="default_order_field" default_order_field="{{ inline_admin_formset.formset.default_order_field }}" default_order_direction="{{ inline_admin_formset.formset.default_order_direction }}"></div>

View File

@ -7,6 +7,13 @@
<button type="submit">Mautic Sync</button> <button type="submit">Mautic Sync</button>
</form> </form>
</div> </div>
<div>
<form action="notif/" method="POST">
{% csrf_token %}
<button type="submit">Notification Test</button>
</form>
</div>
<br /> <br />
{{ block.super }} {{ block.super }}
{% endblock %} {% endblock %}

View File

@ -8,6 +8,7 @@ from django.utils.translation import ugettext_lazy as _
from django.contrib import admin from django.contrib import admin
from rangefilter.filters import DateRangeFilter, DateTimeRangeFilter from rangefilter.filters import DateRangeFilter, DateTimeRangeFilter
from django.urls import path from django.urls import path
from ..automation.mautic import Mautic
SETTING = os.environ['WORKOUTTEST_SETTING'] SETTING = os.environ['WORKOUTTEST_SETTING']
if SETTING == "PROD" : if SETTING == "PROD" :
@ -76,14 +77,20 @@ class CustomerAdmin(admin.ModelAdmin):
def get_urls(self): def get_urls(self):
urls = super().get_urls() urls = super().get_urls()
my_urls = [ my_urls = [
path('mautic/', self.set_mautic), path('mautic/', self.run_mautic),
path('notif/', self.run_notif),
] ]
return my_urls + urls return my_urls + urls
def set_mautic(self, request): def run_notif(self, request):
self.notif.run() self.notif.run()
return HttpResponseRedirect("../") return HttpResponseRedirect("../")
def run_mautic(self, request):
mautic = Mautic()
mautic.syncLang()
return HttpResponseRedirect("../")
admin.site.register(Customer, CustomerAdmin) admin.site.register(Customer, CustomerAdmin)
admin.autodiscover() admin.autodiscover()

View File

@ -4,6 +4,7 @@ from firebase_admin import messaging, exceptions
class FCM: class FCM:
logo_url = 'https://workouttest.com/wp-content/uploads/2020/10/WT_long_logo.png' logo_url = 'https://workouttest.com/wp-content/uploads/2020/10/WT_long_logo.png'
image_base = 'https://admin.aitrainer.app/media/images/'
# default constructor # default constructor
def __init__(self): def __init__(self):
@ -53,10 +54,11 @@ class FCM:
if registration_token == None: if registration_token == None:
return "Registration token is null" return "Registration token is null"
try: try:
notification_image_url = image_url
if image_url == None: if image_url == None:
notification_image_url = self.logo_url notification_image_url = self.logo_url
#registration_token = 'cOqNt8rzo074gbIkBSpCgW:APA91bEBuNi3iVzGKb4JhxqN2j80MoJbNptLHk2qsdeKBQz5grpHtrPPXvDqn5BJVVSaj1nwGPwgN7pi6FIApog_TTP3g1yobgmgpPN6udrYgzILlVPMvdGGFDSDh6gKlczhlTL9NEp0' else:
notification_image_url = self.image_base + '/' + image_url
print(f'image: {notification_image_url}' ) print(f'image: {notification_image_url}' )

View File

@ -2,8 +2,13 @@ import requests
import logging import logging
from django.db import connections from django.db import connections
import datetime import datetime
import os
from ..models.customer import Customer SETTING = os.environ['WORKOUTTEST_SETTING']
if SETTING == "PROD":
from aitrainer_backoffice.aitrainer_backoffice.models.customer import Customer
else:
from aitrainer_backoffice.models.customer import Customer
class Mautic: class Mautic:
@ -13,6 +18,37 @@ class Mautic:
qs = Customer.objects.raw( qs = Customer.objects.raw(
'SELECT * from customer WHERE trial_date < "' + tenDays + '" and trial_date is not null') 'SELECT * from customer WHERE trial_date < "' + tenDays + '" and trial_date is not null')
def syncLang(self):
qs = Customer.objects.raw('SELECT * from customer WHERE lang is not null')
logger = logging.getLogger(__name__)
logger.info("Syncronising lang...")
headers = {
'content-type': "application/x-www-form-urlencoded",
'cache-control': "no-cache"
}
index = 0
for customer in qs:
data = "mauticform[email]=" + customer.email + \
"&mauticform[database_id]=" + str(customer.customer_id) + \
"&mauticform[lang]=" + str(customer.lang) + \
"&mauticform[formId]=3" + \
"&mauticform[formName]=appdatachange"
print(data)
form_url = 'https://mautic.aitrainer.app/form/submit?formId=3'
response = requests.post(form_url, data=data.encode('utf-8'), headers=headers)
print(customer.email + " " +str(response.status_code))
index = index + 1
if index == 2:
break
logger.info("Syncronised customer count: " + str(index))
return True
def sync(self): def sync(self):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.info("Syncronising...") logger.info("Syncronising...")

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-26 11:21+0200\n" "POT-Creation-Date: 2021-10-17 10:52+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,40 +18,22 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: .\controlling\admin\customer.py:58 #: .\controlling\admin\customer.py:65
msgid "Registered" msgid "Registered"
msgstr "" msgstr ""
#: .\controlling\models\customer.py:16 #: .\controlling\admin\frequent_customers.py:22
#: .\controlling\models\frequent_customers.py:9
msgid "name"
msgstr ""
#: .\controlling\models\customer.py:17
#: .\controlling\models\frequent_customers.py:10
msgid "firstname"
msgstr ""
#: .\controlling\models\customer.py:33
msgid "Customer"
msgstr ""
#: .\controlling\models\customer.py:34
msgid "Customers"
msgstr ""
#: .\controlling\models\exercise_type.py:26
msgid "Frequent Exercise"
msgstr ""
#: .\controlling\models\exercise_type.py:27
msgid "Frequent Exercises"
msgstr ""
#: .\controlling\models\frequent_customers.py:26
msgid "Frequent Customer" msgid "Frequent Customer"
msgstr "" msgstr ""
#: .\controlling\models\frequent_customers.py:27 #: .\controlling\admin\frequent_customers.py:23
msgid "Frequent Customers" msgid "Frequent Customers"
msgstr "" msgstr ""
#: .\controlling\admin\frequent_exercises.py:22
msgid "Frequent Exercise"
msgstr ""
#: .\controlling\admin\frequent_exercises.py:23
msgid "Frequent Exercises"
msgstr ""

View File

@ -1,2 +1,2 @@
export $(cat .env | xargs) export $(cat /aitrainer_backoffice.env | xargs)
/usr/local/bin/python /aitrainer_backoffice/aitrainer_backoffice/manage.py runcrons --settings aitrainer_backoffice.settings.deploy >> /var/log/cronjob.log 2>&1 /usr/local/bin/python /aitrainer_backoffice/aitrainer_backoffice/manage.py runcrons --settings aitrainer_backoffice.settings.deploy >> /var/log/cronjob.log 2>&1