Skip to content

38. تمرين عملي: الإصدار 18

38.1. التنفيذ

Image

يتم إنشاء المجلد [impots/http-servers/13] مبدئيًا عن طريق نسخ المجلد [impots/http-servers/12] ثم تعديله جزئيًا.

نبدأ بإضافة معلمة جديدة إلى ملف [configs/parameters]:


…        
        # token csrf
        "with_csrftoken"False,
        # bases gérées MySQL (mysql), PostgreSQL (pgres)
        "databases"["mysql""pgres"],
        # préfixe des URL de l'application
        # mettre la chaîne vide si on ne veut pas de préfixe ou /préfixe sinon
        "prefix_url""/do",
        # url racine du serveur Apache - mettre la chaîne vide pour une exécution en-dehors d'Apache
        "application_root""/impots"

السطر 10: سيمثل المعامل [application_root] الاسم المستعار WSGI للخادم الظاهري Apache.

باستخدام هذه المعلمة، يمكننا تصحيح توجيه [responses/HtmlResponse] الذي تسبب في الخطأ:

Image



# now it's time to generate the URL redirection, not forgetting the CSRF token if requested
        if config['parameters']['with_csrftoken']:
            csrf_token = f"/{generate_csrf()}"
        else:
            csrf_token = ""
 
        # redirect response
        return redirect(f"{config['parameters']['application_root']}{config['parameters']['prefix_url']}{ads['to']}{csrf_token}")
, status.HTTP_302_FOUND
  • السطر 9: أضفنا جذر التطبيق إلى بداية عنوان URL الهدف لإعادة التوجيه؛

نحتاج أيضًا إلى تصحيح جميع الأجزاء بحيث تبدأ عناوين URL التي تحتوي عليها بجذر التطبيق (أو الاسم المستعار لـ WSGI):

Image

جزء [v-authentication]


<!-- form HTML - post its values with the [authenticate-user] action -->
<form method="post" action="{{modèle.application_root}}{{modèle.prefix_url}}/authentifier-utilisateur{{modèle.csrf_token}}"
>
 
    <!-- title -->
    <div class="alert alert-primary" role="alert">
        <h4>Veuillez vous authentifier</h4>
    </div>

 
</form>

جزء [v-calcul-impot]


<!-- form HTML posted -->
<form method="post" action="{{modèle.application_root}}{{modèle.prefix_url}}/calculer-impot{{modèle.csrf_token}}">
    <!-- 12-column message on blue background -->
    
 
</form>

مقتطف [v-liste-simulations]



 
{% if modèle.simulations is defined and modèle.simulations|length!=0 %}

 
<!-- simulation table -->
<table class="table table-sm table-hover table-striped">
    
    <tr>
        <th scope="row">{{simulation.id}}</th>
        <td>{{simulation.marié}}</td>
        <td>{{simulation.enfants}}</td>
        <td>{{simulation.salaire}}</td>
        <td>{{simulation.impôt}}</td>
        <td>{{simulation.surcôte}}</td>
        <td>{{simulation.décôte}}</td>
        <td>{{simulation.réduction}}</td>
        <td>{{simulation.taux}}</td>
        <td><a href="{{modèle.application_root}}{{modèle.prefix_url}}/supprimer-simulation/{{simulation.id}}{{modèle.csrf_token}}">Supprimer</a></td>
    </tr>
    {% endfor %}
    </tr>
    </tbody>
</table>
{% endif %}

جزء [v-menu]


<!-- bootstrap menu -->
<nav class="nav flex-column">
    <!-- display a list of links HTML -->
    {% for optionMenu in modèle.optionsMenu %}
    <a class="nav-link" href="{{modèle.application_root}}{{modèle.prefix_url}}{{optionMenu.url}}{{modèle.csrf_token}}">{{optionMenu.text}}</a>
    {% endfor %}
</nav>

تستخدم جميع الأجزاء أعلاه نموذج [model.application_root]. حاليًا، لا يوجد مفتاح [application_root] في النماذج التي تم إنشاؤها بواسطة فئات النموذج.

Image

تصبح فئة [AbstractBaseModelForView]، وهي الفئة الأم لجميع الفئات التي تنشئ قالبًا، كما يلي:

from abc import abstractmethod

from flask import Request
from flask_wtf.csrf import generate_csrf
from werkzeug.local import LocalProxy

from InterfaceModelForView import InterfaceModelForView

class AbstractBaseModelForView(InterfaceModelForView):

    @abstractmethod
    def get_model_for_view(self, request: Request, session: LocalProxy, config: dict, résultat: dict) -> dict:
        pass

    def update_model(self, modèle: dict, config: dict):
        #  token calculation CSRF
        if config['parameters']['with_csrftoken']:
            csrf_token = f"/{generate_csrf()}"
        else:
            csrf_token = ""
        #  update the model passed in parameter
        modèle.update({
            #  csrf token
            'csrf_token': csrf_token,
            #  prefix_url
            'prefix_url': config["parameters"]["prefix_url"],
            #  application_root
            'application_root': config["parameters"]["application_root"],
        })
  • السطر 15: الطريقة [update_model] مسؤولة عن إضافة ما يلي إلى قالب العرض:
    • السطر 24: رمز CSRF؛
    • السطر 26: بادئة عنوان URL؛
    • السطر 28: جذر التطبيق أو الاسم المستعار لـ WSGI؛

تستدعي الفئات الفرعية الأربع الفئة الأصلية باستخدام الكود التالي:



        # actions possibles à partir de la vue
        modèle['actions_possibles'] = ["afficher-vue-authentification""authentifier-utilisateur"]
 
        # finition du modèle par la classe parent
        super().update_model(modèle, config)
 
        # on rend le modèle
        return modèle
  • السطر 6: تستدعي كل فئة فرعية فئتها الأم لتحديث النموذج الذي أنشأته؛

الإصدار 18 جاهز. نعيد استخدام الخادمين الافتراضيين لـ Apache من الإصدار 17 ونقوم بتعديلهما:

Image

تم تعديل ملفَي [flask-impots-withXX.conf] في مكان واحد فقط:


# dossier du script .wsgi
define ROOT "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-servers/13/apache"
 
# nom du site web configuré par ce fichier
# ici il s'appellera flask-impots-withmysql
# les URL seront du type http(s)://flask-impots-withmysql/path
define SITE "flask-impots-withmysql"
 
# mettre l'adresse IP 127.0.0.1 pour site SITE dans c:/windows/system32/drivers/etc/hosts
 
# mettre ici les chemins des bibliothèques Python à utiliser - les séparer par des virgules
# ici les bibliothèques d'un environnement virtuel Python
WSGIPythonPath  "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages"
 
# Python Home - nécessaire uniquement s'il y a plusieurs versions de Python installées
# WSGIPythonHome "C:/Program Files/Python38"
 
# URL HTTP
<VirtualHost *:80>
    # avec l'alias / les URL auront la forme /{prefixe_url}/action/...
    # avec l'alias /impots les URL auront la forme /impots/{prefixe_url}/action/...
    # où [prefixe_url] est défini dans parameters.py
    WSGIScriptAlias /impots "${ROOT}/main_withmysql.wsgi"
    …
</VirtualHost>
 
# URL sécurisées avec HTTPS
<VirtualHost *:443>
    # avec l'alias / les URL auront la forme /{prefixe_url}/action/...
    # avec l'alias /impots les URL auront la forme /impots/{prefixe_url}/action/...
    # où [prefixe_url] est défini dans parameters.py
    WSGIScriptAlias /impots "${ROOT}/main_withmysql.wsgi"
    ..
 
</VirtualHost>
  • السطر 12: نحن نستخدم الآن الدليل [taxes/http-servers/13/apache].

نحن جاهزون لاختبار الإصدار 18 الذي يعمل على Apache. التكوين كما يلي:

  • الاسم المستعار لـ WSGI هو /impots في ملفات تكوين الخادم الافتراضي؛
  • في ملف التكوين [configs/parameters]، المعلمات هي كما يلي:

        # token csrf
        "with_csrftoken"False,
        # préfixe des URL de l'application
        # mettre la chaîne vide si on ne veut pas de préfixe ou /préfixe sinon
        "prefix_url""/do",
        # url racine du serveur Apache - mettre la chaîne vide pour une exécution en-dehors d'Apache
        "application_root""/impots"

نقوم بتشغيل خادم Apache ونظامي إدارة قواعد البيانات. نطلب عنوان URL [https://flask-impots-withmysql/impots/do]. يكون رد الخادم كما يلي:

Image

لقد تمكنا من عرض صفحة المصادقة، التي لم نتمكن من الوصول إليها في الإصدار السابق. أما باقي أجزاء التطبيق، فهي تعمل بشكل طبيعي.

الآن نختبر الخادم الافتراضي الآخر. نطلب عنوان URL [https://flask-impots-withpgres/impots/do]. استجابة الخادم هي كما يلي:

Image

تخدم مفاهيم الأسماء المستعارة WSGI وبادئات عناوين URL نفس الغرض. أحد هذين المفهومين زائد عن الحاجة. وبالتالي، لإضافة البادئة [/impots/do] إلى عناوين URL لخادم Apache، هناك ثلاث طرق للقيام بذلك:

1 – [WGSIAlias /impots] و [prefix_url=’/do’];

2 – [WGSIAlias /] و [prefix_url=’/impots/do’];

3 – [WGSIAlias /impots/do] و [prefix_url=’’]؛

38.2. اختبارات وحدة التحكم

نستخدم اختبارات وحدة التحكم الخاصة بالعميل [http-clients/09] مرة أخرى:

Image

  • يجب تعديل عنوان URL للخادم في التكوينات [1] و [3]؛
  • يجب إجراء تغيير على طبقة [dao] بحيث تدعم بروتوكول HTTPS لخادم Apache؛

في ملفات [config]، يصبح عنوان URL للخادم كما يلي:


        "server": {
            # "urlServer": "http://127.0.0.1:5000",
            # "urlServer": "http://127.0.0.1:5000/do",
            "urlServer""https://flask-impots-withmysql/impots/do",
            "user": {
                "login""admin",
                "password""admin"
            },
            "url_services": {
                
            }
        },
        # mode debug
        "debug"True,
        # csrf_token
        "with_csrftoken"False,
  • السطر 4: عنوان URL الجديد للخادم. لأول مرة في هذا المستند، يستخدم العميل بروتوكول HTTPS؛

تتطور فئة [ImpôtsDaoWihHttpSession] في طبقة [dao] على النحو التالي:

    
    # étape request / response
    def get_response(self, method: str, url_service: str, data_value: dict = None, json_value=None):
        #  [method]: HTTP GET or POST method
        #  [url_service] : URL of service
        #  [data]: POST parameters in x-www-form-urlencoded
        #  [json]: POST parameters in json
        #  [cookies]: cookies to include in the request

        #  you must have a XML or JSON session, otherwise you won't be able to handle the response
        if self.__session_type not in ['json', 'xml']:
            raise ImpôtsError(73, "il n'y a pas de session valide en cours")

        #  we add the CSRF token to the URL service token
        if self.__csrf_token:
            url_service = f"{url_service}/{self.__csrf_token}"

        #  query execution
        response = requests.request(method,
                                    url_service,
                                    data=data_value,
                                    json=json_value,
                                    cookies=self.__cookies,
                                    allow_redirects=True,
                                    #  for the https protocol
                                    verify=False)

        #  debug mode?
        if self.__debug:
            #  logger
            if not self.__logger:
                self.__logger = self.__config['logger']
            #  log on
            self.__logger.write(f"{response.text}\n")

        

        #  we return the result
        return résultat['réponse']
  • في السطر 26، نضيف المعلمة [verify=False] بسبب بروتوكول HTTPS الذي يستخدمه خادم Apache. تدعم الوحدة النمطية [requests] (السطر 19) بروتوكول HTTPS بشكل أصلي. بشكل افتراضي، تتحقق الوحدة من صحة شهادة الأمان المرسلة من خادم HTTPS وترفع استثناءً إذا كانت الشهادة المستلمة غير صالحة. وهذا هو الحال هنا، حيث يرسل خادم Apache الخاص بـ Laragon شهادة موقعة ذاتيًا. لتجنب الاستثناء، نستخدم المعلمة [verify=False] لإخبار الوحدة النمطية [requests] بعدم رفع استثناء. ثم تعرض [requests] ببساطة تحذيرًا على وحدة التحكم.

بعد إجراء هذه التغييرات، من المفترض أن تعمل جميع اختبارات وحدة التحكم.