Шаблон этот пользователь: Общий доступ к шаблону. Помощь – Создать мем Пользователь генератор мемов

Содержание

Шаблоны пользователей — ISPWiki


Шаблоны позволяют задать значения некоторых параметров, что поможет сэкономить время при заполнении форм создания пользователей. Модуль «Шаблоны пользователей»
T-bullet.png Просмотр списка шаблонов пользователей
T-new.png Создание нового шаблона
T-edit.png Редактирование параметров шаблона
T-delete.png Удаление шаблонов

Просмотр списка шаблонов пользователей

  • Название - наименование шаблона, которое будет отображаться в списке формы создания пользователя
  • Тип - тип пользователей, для создания которых используется шаблон: пользователь или реселлер (доступно только в ISPmanager Pro).
  • Доступ к функциям
    - выбранный шаблон группы прав, ранее созданный в разделе "доступы к функциям"
  • Использование - сколько раз был использован шаблон для создания пользователей панели управления.
  • Диск - размер дискового пространства, которое может могут занимать файлы пользователя, созданного на основе этого шаблона.
  • Web-домены - количество web-доменов, которыми может управлять пользователь, созданный на основе этого шаблона.
  • Доменные имена - количество доменов, которыми может управлять пользователь, созданный на основе этого шаблона.
  • Базы данных - количество баз данных, которыми может управлять пользователь, созданный на основе этого шаблона.
  • Параметры - параметры, доступные пользователю, созданному на основе этого шаблона:
P-shell.png - пользователь может осуществлять доступ к Shell.
P-cgi.png - пользователь может использовать CGI для своих Web-доменов.
P-php.png
- пользователь может использовать PHP для своих Web доменов.
P-ssi.png - пользователь может использовать SSI для своих Web-доменов.
P-ssl.png - пользователь может настраивать возможность использования безопасного подключения по протоколу HTTPs к своим Web-доменам.

Создание шаблона

Чтобы создать новый шаблон пользователя (реселлера), нажмите кнопку "Создать" и заполните поля следующей формы, состоящей из двух вкладок:

Вкладка Основное

P-ssl.png Модуль «Шаблоны пользователей»
  • Название - укажите название шаблона.
  • Группа прав - выбор доступа к функциям , к которому будет относиться пользователь, созданный по данному шаблону
  • Тип - выберите тип создаваемого шаблона - пользователь или реселлер (доступно только в ISPmanager Business).
  • Резервное копирование - позволяет включить опцию резервного копирования(добавлено в версии 5.162)

Вкладка Ограничения

  • Диск - ограничение на размер дискового пространства, занимаемого файлами пользователя. Сюда также входят WWW домены, файлы FTP аккаунтов и почтовые ящиками.
  • Базы данных- ограничение на количество баз данных, которыми может управлять пользователь.
  • Пользователи баз данных - ограничение на количество пользователей баз данных, которыми может управлять пользователь.
  • FTP-пользователи - ограничение на количество FTP аккаунтов, которые может создать пользователь.
  • Web-домены - ограничение на количество Web-доменов, которыми может управлять пользователь.
  • Почтовые домены - ограничение на количество почтовых доменов, которыми может управлять пользователь.
  • Почтовые ящики - ограничение на количество ящиков электронной почты, которых может создать пользователь.

Вкладка "Ресурсы"

P-ssl.png Модуль «Реселлеры»
  • Процессорное время
    - укажите ограничение на использование процессорного времени процессами пользователя.
  • Оперативная память - укажите максимальное количество оперативной памяти, которое может быть выделено процессу, запущенному от имени пользователя.
  • Процессов пользователя - укажите максимальное количество одновременно запущенных в системе процессов, выполняющихся от имени пользователя.
  • Одновременных соединений на сессию - укажите максимальное количество одновременных соединений с одного IP-адреса в час, которое будет обрабатываться web-сервером
  • Обработчиков Apache - укажите максимальное количество обработчиков web-сервера Apache, обслуживающих web-домен.
  • Одновременных MySQL-соединений - укажите максимальное количество одновременных соединении, которые может открыть MySQL-пользователь за один час.
  • MySQL-соединений - укажите максимальное количество новых соединении, которые может открыть MySQL-пользователь за один час.
  • Запросов к MySQL - укажите максимальное количество команд, которые может MySQL-пользователь за один час.
  • Update-запросов MySQL
    - укажите максимальное количество команд, которые меняют таблицу или базу данных, которые может выполнять MySQL-пользователь за один час.

Вкладка Доступ

P-ssl.png Модуль «Шаблоны пользователей»
  • Может использовать SSL - пользователь сможет настраивать безопасное соединение по протоколу HTTPs для своих web-доменов.
  • Может использовать CGI - пользователь сможет использовать CGI (Common Gateway Interface) для своих web-доменов.
  • Может использовать PHP как модуль Apache - пользователь сможет использовать PHP в режиме модуля Apache для своих web-доменов.
  • Может использовать PHP в режиме CGI - пользователь сможет использовать PHP в режиме CGI для своих web-доменов.
  • Доступ к shell - пользователь сможет использовать shell для доступа к серверу.

Редактирование параметров шаблона

Чтобы изменить параметры существующего шаблона, выберите его из списка, нажмите кнопку "Изменить" и выполните редактирование. Форма для редактирования аналогична форме создания нового шаблона.

Внимание!!! На форме редактирования установлен флаг "Применить изменения". Изменения, сделанные в шаблоне, будут применены ко всем пользователям, созданным на основе этого шаблона. Включая применение прав.

Настройка прав пользователей в шаблонах

С версии 5.177 добавлена возможность выбора в шаблонах прав, с которыми будет создан пользователь в панели. Для назначения прав в шаблоне необходимо:

1 Создать пользователя в панели, с которого будет формироваться список прав или можно будет использовать существующего

2 Перейти в раздел "доступ к функциям"

3 Создать группы прав, выбрав ранее созданного пользователя или существующего пользователя, который не будет удален из панели в дальнейшем

Внимание! Группа прав, созданная с функцией "Применять для всех пользователей" недоступна для использования в шаблонах.

4 Выбрать группу и настроить необходимые права, которые бутут иметь пользователи, состоящие в данной группе

5 Перейти в раздел Шаблоны

6 Открыть на редактирование существующий шаблон или создать новый

7 На открывшейся форме создания/редактирования шаблона выбрать ранее созданную группу в поле

"Группа прав"

После применения настроек все пользователи, созданные или использующие данный шаблон будут иметь права, настроенные в группе, которую выбрали в шаблоне. Настройка прав у конкретного пользователя имеет приоритет выше. Если необходимо для пользователя включить какую-либо функцию не меняя шаблон, то нужно использовать настройки прав пользователя, которые расположены в разделе "Учетные записи" -> Пользователи -> Права

Из раздела шаблоны можно изменить права группы. Для этого нужно выбрать шаблон в списке и нажать на кнопку "Права". Откроется список прав группы используемой в шаблоне.

Посмотреть пользователей определенной группы можно в разделе "доступ к функциям" -> Пользователи

Удаление шаблонов

Чтобы удалить шаблон, выберите его из списка и нажмите кнопку "Удалить". Для предотвращения случайного удаления программа попросит подтвердить или отменить ваши действия. После нажатия кнопки "ОК" выделенный шаблон будет удален.

Исправления

Внимание!

В версиях 5.169.3 и 5.172 добавлен фикс, принудительно включающий опцию резервного копирования во всех существующих шаблонах учётных записей без применения к существующим пользователям.

Данным фиксом восстанавливается логика создания пользователей по существующим шаблонам до внесения изменений в версии 5.162.

Для предотвращения выполнения фикса, перед обновлением ISPmanager до указанных выше версий необходимо в файл /usr/local/mgr5/var/fixlist_ispmgr добавить строку fix_preset_backup.

«......»

Эта форма — не обращение в поддержку.
Мы не можем идентифицировать вас и ответить на ваше сообщение.

Страница профиля и аватары (издание 2018) / Habr

blog.miguelgrinberg.com


Miguel Grinberg



<<< предыдущая следующая >>>

Эта статья является переводом шестой части нового издания учебника Мигеля Гринберга, выпуск которого автор планирует завершить в мае 2018.Прежний перевод давно утратил свою актуальность.

Я, со своей стороны, постараюсь не отставать с переводом.



Это шестой выпуск серии Flask Mega-Tutorial, в котором я расскажу вам, как создать страницу профиля пользователя.

Для справки ниже приведен список статей этой серии.


Примечание 1: Если вы ищете старые версии данного курса, это здесь.

Примечание 2: Если вдруг Вы хотели бы выступить в поддержку моей(Мигеля) работы в этом блоге, или просто не имеете терпения дожидаться неделю статьи, я (Мигель Гринберг)предлагаю полную версию данного руководства упакованную электронную книгу или видео. Для получения более подробной информации посетите learn.miguelgrinberg.com.

Эта глава будет посвящена добавлению страниц профилей пользователей в приложение. Страница профиля пользователя-это страница, на которой представлена информация о пользователе, как правило, введенной самими пользователями. Я покажу вам, как создавать страницы профилей для всех пользователей динамически, а затем я добавлю небольшой редактор профилей, который пользователи могут использовать для ввода своей информации.

Ссылки GitHub для этой главы: Browse, Zip, Diff.


Страница профиля пользователя

Чтобы создать страницу профиля пользователя, давайте сначала напишем новую функцию просмотра, которая будет отображаться в /user/<имя пользователя> URL.

@app.route('/user/<username>')
@login_required
def user(username):
    user = User.query.filter_by(username=username).first_or_404()
    posts = [
        {'author': user, 'body': 'Test post #1'},
        {'author': user, 'body': 'Test post #2'}
    ]
    return render_template('user.html', user=user, posts=posts)

Декоратор @app.route, который я использовал для объявления этой функции просмотра, немного отличается от предыдущих. В этом случае у меня есть динамический компонент, который обозначается как компонент URL-адреса <username>, который заключен в треугольные скобки,<и>. Когда маршрут имеет динамический компонент, Flask принимает любой текст в этой части URL-адреса и вызывает функцию просмотра с фактическим текстом в качестве аргумента. Например, если клиентский браузер запрашивает URL: /user/susan, функция view будет вызываться с именем пользователя в качестве аргумента, установленным на «susan». Эта функция просмотра будет доступна только для зарегистрированных пользователей, поэтому я добавил обработчик @login_required из Flask-Login.

Реализация этой функции просмотра довольно проста. Сначала я пытаюсь загрузить пользователя из базы данных, используя запрос по имени пользователя. Вы уже видели, что запрос базы данных может быть выполнен путем вызова

all(), если вы хотите получить все результаты, или first(), если вы хотите получить только первый результат или, если же ничего, соответствующего критериям поиска, не найдется, то эти методы вернут None. В этой функции представления я использую вариант first(), называемый first_or_404(), который работает точно так же, как first(), когда есть результаты, но в случае отсутствия результатов автоматически обратно клиенту отправляется ошибка 404. Выполняя запрос таким образом, я не могу проверить, возвратился ли запрос пользователя, потому что, когда имя пользователя не существует в базе данных, функция не вернется, и вместо этого будет вызвано исключение 404.

Если запрос базы данных не вызывает ошибку 404, это означает, что был найден пользователь с указанным именем пользователя. Затем я инициализирую временный список сообщений для этого пользователя, наконец, создаю новый шаблон user.html, которому передаю объект пользователя и список сообщений.

Шаблон user.html показан ниже:

{% extends "base.html" %}

{% block content %}
    <h2>User: {{ user.username }}</h2>
    <hr>
    {% for post in posts %}
    <p>
    {{ post.author.username }} says: <b>{{ post.body }}</b>
    </p>
    {% endfor %}
{% endblock %}

Страница профиля завершена, но ссылка на нее не существует нигде на веб-сайте. Чтобы пользователям было проще проверить собственный профиль, я добавлю ссылку на него в панели навигации вверху:

<div>
  Microblog:
  <a href="{{ url_for('index') }}">Home</a>
  {% if current_user.is_anonymous %}
  <a href="{{ url_for('login') }}">Login</a>
  {% else %}
  <a href="{{ url_for('user', username=current_user.username) }}">Profile</a>
  <a href="{{ url_for('logout') }}">Logout</a>
  {% endif %}
</div>

Единственное интересное изменение здесь — вызов url_for(), который используется для создания ссылки на страницу профиля. Поскольку функция просмотра профиля пользователя принимает динамический аргумент, функция url_for() получает значение для него как аргумент ключевого слова. Поскольку это ссылка, которая указывает на профиль пользователя в журнале, я могу использовать current_user Flask-Login для генерации правильного URL-адреса.

Попробуйте! Нажав ссылку «Профиль» вверху страницы, вы попадете на свою страницу пользователя. На этом этапе нет ссылок, которые будут отображаться на странице профиля других пользователей, но если вы хотите получить доступ к этим страницам, вы можете ввести URL-адрес вручную в адресной строке браузера. Например, если у вас есть пользователь с именем «john», зарегистрированный в вашем приложении, вы можете просмотреть соответствующий профиль пользователя, введя http://localhost:5000/user/ john в адресной строке.


Аватары

Я уверен, вы согласитесь с тем, что страницы профиля, которые я только что построил, довольно скучны. Чтобы сделать их более интересными, я собираюсь добавить пользовательские аватары, но вместо того, чтобы иметь дело с возможно большой коллекцией загруженных изображений на сервере, я собираюсь использовать сервис Gravatar для предоставления изображений для всех пользователей.

Сервис Gravatar очень прост в использовании. Чтобы запросить изображение для данного пользователя, URL-адрес с форматом https://www.gravatar.com/avatar/, где <hash> — хеш MD5 адреса электронной почты пользователя. Ниже вы можете увидеть, как получить URL-адрес Gravatar для пользователя с адресом электронной почты [email protected]:

>>> from hashlib import md5
>>> 'https://www.gravatar.com/avatar/' + md5(b'[email protected]').hexdigest()
'https://www.gravatar.com/avatar/d4c74594d841139328695756648b6bd6'

Если вы хотите увидеть фактический пример, можно использовать мой собственный URL-адрес Gravatar — https://www.gravatar.com/avatar/729e26a2a2c7ff24a71958d4aa4e5f35 ( 'https://www.gravatar.com/avatar/4f3699b436c12996ae54771200f21888' ). Вот что Gravatar возвращает для этого URL:

По умолчанию возвращенный размер изображения составляет 80x80 пикселей, но другой размер можно запросить, добавив аргумент s в строку запроса URL. Например, чтобы получить мой собственный аватар в виде изображения размером 128x128, URL-адрес: https://www.gravatar.com/avatar/729e26a2a2c7ff24a71958d4aa4e5f35?s=128.

Другим интересным аргументом, который может быть передан Gravatar в качестве аргумента строки запроса, является d, который определяет, какое изображение Gravatar предоставляет пользователям, у которых нет аватара, зарегистрированного в службе. Мой любимый называется «идентификатор», который возвращает приятный геометрический дизайн, который отличается для каждого письма. Например:

Обратите внимание, что некоторые расширения веб-браузера, такие как Ghostery, блокируют изображения Gravatar, поскольку они считают, что Automattic (владельцы Gravatar) могут определять, какие сайты вы посещаете, на основе запросов, которые они получают для вашего аватара. Если вы не видите аватары в своем браузере, скорее всего проблема в расширениях браузера.

Поскольку аватары связаны с пользователями, имеет смысл добавить логику, которая генерирует URL-адреса аватара для пользовательской модели.

from hashlib import md5
# ...

class User(UserMixin, db.Model):
    # ...
    def avatar(self, size):
        digest = md5(self.email.lower().encode('utf-8')).hexdigest()
        return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format(
            digest, size)

Новый метод avatar()класса User возвращает URL-адрес изображения аватара пользователя, масштабируется до требуемого размера в пикселях. Для пользователей, у которых нет зарегистрированного аватара, будет создано изображение «идентификатор». Чтобы сгенерировать хэш MD5, я конвертирую адрес электронной почты в нижний регистр, поскольку этого требует Gravatar. Затем, конвертирую полученный hash-объект в шестнадцатеричную строку (метод .hexdigest()), прежде чем передавать ее хэш-функции.

Если вы заинтересованы в ознакомлении с другими вариантами, предлагаемыми службой Gravatar, посетите их сайт документации.

Следующий шаг — вставить изображения аватара в шаблон профиля пользователя:

{% extends "base.html" %}

{% block content %}
    <table>
        <tr valign="top">
            <td><img src="{{ user.avatar(128) }}"></td>
            <td><h2>User: {{ user.username }}</h2></td>
        </tr>
    </table>
    <hr>
    {% for post in posts %}
    <p>
    {{ post.author.username }} says: <b>{{ post.body }}</b>
    </p>
    {% endfor %}
{% endblock %}

Большой плюс заключается в том, что пользовательский класс отвечает за возвращение URL-адресов аватаров.И если в какой-то день я решу, что аватары Gravatar не то, что я хочу, я могу просто переписать метод avatar(), чтобы возвращать разные URL-адреса, и все шаблоны начнут показывать новые аватары автоматически.

У меня есть хороший большой аватар в верхней части страницы профиля пользователя, но на самом деле нет причин останавливаться на достигнутом. У меня есть несколько сообщений от пользователя внизу, в которых каждый может иметь маленький аватар. Конечно, для страницы профиля пользователя все сообщения будут иметь один и тот же аватар, но тогда я могу реализовать ту же функциональность на главной странице, а затем каждый пост будет украшен аватаром автора, и это будет выглядеть очень красиво.

Чтобы показать аватары для отдельных сообщений, мне просто нужно сделать еще одно небольшое изменение в шаблоне:

{% extends "base.html" %}

{% block content %}
    <table>
        <tr valign="top">
            <td><img src="{{ user.avatar(128) }}"></td>
            <td><h2>User: {{ user.username }}</h2></td>
        </tr>
    </table>
    <hr>
    {% for post in posts %}
    <table>
        <tr valign="top">
            <td><img src="{{ post.author.avatar(36) }}"></td>
            <td>{{ post.author.username }} says:<br>{{ post.body }}</td>
        </tr>
    </table>
    {% endfor %}
{% endblock %}

Вот так у Сьюзен, которой нет

(Прим. переводчика) А вот так с реальным аккаунтом Gravatar.


Использование sub-templates Jinja2

Я разработал страницу профиля пользователя, чтобы отображать сообщения, написанные пользователем, вместе со своими аватарами. Теперь я хочу, чтобы страница индекса также отображала сообщения с похожим расположением. Я мог бы просто закопипастить часть шаблона, которая касается рендеринга сообщения, но это не правильно, потому что позже, если я решу внести изменения в этот макет, мне придется помнить об обновлении обоих шаблонов.

Вместо этого я собираюсь сделать подшаблон, который просто отображает одно сообщение, а затем я буду ссылаться на него как с шаблонов user.html, так и с index.html. Для начала я могу создать подшаблон, с разметкой HTML для одного сообщения. Назову, пожалуй, это шаблонное нечто app/templates/_post.html. Префикс `_' — это просто соглашение об именах, которое помогает распознавать, какие файлы шаблонов являются подшаблонами.

<table>
    <tr valign="top">
        <td><img src="{{ post.author.avatar(36) }}"></td>
        <td>{{ post.author.username }} says:<br>{{ post.body }}</td>
    </tr>
</table>

Чтобы вызвать этот подшаблон из шаблона user.html, я использую оператор include Jinja2:

{% extends "base.html" %}

{% block content %}
    <table>
        <tr valign="top">
            <td><img src="{{ user.avatar(128) }}"></td>
            <td><h2>User: {{ user.username }}</h2></td>
        </tr>
    </table>
    <hr>
    {% for post in posts %}
        {% include '_post.html' %}
    {% endfor %}
{% endblock %}

Страница index приложения на самом деле еще не сформирована, поэтому я пока не собираюсь добавлять эту функциональность.


Более интересные профили

Одна из проблем, с которой сталкиваются новые страницы профиля пользователя, заключается в том, что они на самом деле многого не показывают. Пользователи любят рассказывать о чем то на этих страницах, поэтому я позволю им написать что-то о себе, чтобы показать здесь.
Я также буду следить за тем, когда последний раз каждый пользователь обращался к сайту, а также показывать его на странице своего профиля.

Первое, что мне нужно сделать для поддержки всей этой дополнительной информации, — это расширить таблицу пользователей в базе данных двумя новыми полями:

class User(UserMixin, db.Model):
    # ...
    about_me = db.Column(db.String(140))
    last_seen = db.Column(db.DateTime, default=datetime.utcnow)

Каждый раз, когда база данных изменяется, необходимо создать миграцию базы данных. В главе 4 я показал вам, как настроить приложение для отслеживания изменений базы данных с помощью сценариев миграции. Теперь у меня есть два новых поля, которые я хочу добавить в базу данных, поэтому первым шагом будет создание сценария миграции:



Прим. переводчика: советую команды, да и тексты набирать самому. Получать ошибки/опечатки. Исправлять их. Все это процесс обучения, который сильно поможет в будущем.

Вот пример ошибки:

(venv) C:\microblog>flask db upgrade
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.

(venv) C:\microblog>flask db mograte -m "new fields in user model"
Usage: flask db [OPTIONS] COMMAND [ARGS]...

Error: No such command "mograte".

продолжаем...



(venv) C:\microblog>flask db migrate -m "new fields in user model"
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added column 'user.about_me'
INFO  [alembic.autogenerate.compare] Detected added column 'user.last_seen'
Generating C:\microblog\migrations\versions\45833c85abc8_new_fields_in_user_model.py ... done

(venv) C:\microblog>

Результат команды migrate выглядит хорошо, поскольку он показывает, что были обнаружены два новых поля в классе User. Теперь я могу применить это изменение к базе данных:

(venv) C:\microblog>flask db upgrade
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade f8c5670875a3 -> 45833c85abc8, new fields in user model

Надеюсь, вы понимаете, насколько полезно работать с инфраструктурой миграции. Любые пользователи, которые находились в базе данных, все еще существуют, структура миграции оперативно применяет изменения в сценарии миграции, не разрушая никаких данных.

На следующем шаге я собираюсь добавить эти два новых поля в шаблон профиля пользователя:

{% extends "base.html" %}

{% block content %}
    <table>
        <tr valign="top">
            <td><img src="{{ user.avatar(128) }}"></td>
            <td>
                <h2>User: {{ user.username }}</h2>
                {% if user.about_me %}<p>{{ user.about_me }}</p>{% endif %}
                {% if user.last_seen %}<p>Last seen on: {{ user.last_seen }}</p>{% endif %}
            </td>
        </tr>
    </table>
    ...
{% endblock %}

Обратите внимание, что я обертываю эти два поля в условных выражениях Jinja2, потому что хочу, чтобы они были видимыми, если они заполнены. На этом этапе эти два новых поля пусты для всех пользователей, поэтому вы не увидите эти поля, если запустите приложение прямо сейчас.


Запись последнего времени посещения для пользователя

Начнем с поля last_seen, более простого из двух. То, что я хочу сделать, это записать текущее время в этом поле для конкретного пользователя всякий раз, когда пользователь отправляет запрос на сервер.
Добавление логина для установки этого поля во всевозможные функции просмотра, которые могут быть запрошены у браузера, очевидно, нецелесообразно, но выполнение немного общей логики перед запросом, отправляемым в функцию просмотра, является общей задачей в веб-приложениях, которые Flask предлагает его как родную функцию. Взгляните на решение:

from datetime import datetime

@app.before_request
def before_request():
    if current_user.is_authenticated:
        current_user.last_seen = datetime.utcnow()
        db.session.commit()

Декоратор @before_request от Flask регистрирует декорированную функцию, которая должна быть выполнена непосредственно перед функцией просмотра. Это очень полезно, потому что теперь я могу вставить код, который я хочу выполнить перед любой функцией просмотра в приложении, и я могу использовать его в одном месте. Реализация просто проверяет, зарегистрирован ли current_user, и в этом случае устанавливает последнее поле в текущее время. Я уже упоминал об этом, серверное приложение должно работать в единых единицах времени, а стандартная практика — использовать часовой пояс UTC. Использование локального времени системы не является хорошей идеей, потому что то, что происходит в базе данных, зависит от вашего местоположения.
Последним шагом является фиксация сеанса базы данных, так что сделанное выше изменение записывается в базу данных. Если вам интересно, почему перед фиксацией нет db.session.add(), подумайте, что когда вы ссылаетесь на current_user, Flask-Login будет вызывать функцию обратного вызова загрузчика пользователя, который будет запускать запрос базы данных, который поместит целевого пользователя в сеанс базы данных. Таким образом, вы можете добавить пользователя снова в эту функцию, но это не обязательно, потому что он уже существует.

Если вы просмотрите страницу своего профиля после внесения этого изменения, вы увидите строку "Last seen on" (Последнее посещение) с временем, близким к текущему.
И если вы перейдете от страницы профиля и затем вернетесь, вы увидите, что время постоянно обновляется.

Тот факт, что я храню эти временные метки в часовом поясе UTC, делает время, отображаемое на странице профиля, также в формате UTC. До кучи ко всему этому, формат времени — это не то, что вы ожидаете, поскольку видим отображение внутреннего представление объекта datetime Python. На данный момент я не буду беспокоиться об этих двух проблемах, так как я расскажу о теме обработки дат и времени в веб-приложении в следующей главе.


Редактор профиля

По хорошему пользователям нужно предоставить форму, в которой они могут ввести некоторую информацию о себе. Форма позволит пользователям изменить свой логин и другие данные, а также написать что-то о себе, чтобы быть сохраненным в новом поле about_me. Давайте напишем класс для такой формы:

from wtforms import StringField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Length

# ...

class EditProfileForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired()])
    about_me = TextAreaField('About me', validators=[Length(min=0, max=140)])
    submit = SubmitField('Submit')

Я использую новый тип поля и новый валидатор в этой форме. Для поля «About» я использую TextAreaField, который представляет собой многострочное поле, в котором пользователь может вводить текст. Чтобы проверить это поле, я использую Length, который будет следить за тем, чтобы введенный текст находился между 0 и 140 символами, который является пространством, которое я выделил для соответствующего поля в базе данных.

Шаблон, который отображает эту форму, показан ниже:


app/templates/edit_profile.html
{% extends "base.html" %}

{% block content %}
    <h2>Edit Profile</h2>
    <form action="" method="post">
        {{ form.hidden_tag() }}
        <p>
            {{ form.username.label }}<br>
            {{ form.username(size=32) }}<br>
            {% for error in form.username.errors %}
            <span>[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.about_me.label }}<br>
            {{ form.about_me(cols=50, rows=4) }}<br>
            {% for error in form.about_me.errors %}
            <span>[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>{{ form.submit() }}</p>
    </form>
{% endblock %}

И, наконец, вот функция, которая связывает все вместе:

from app.forms import EditProfileForm

@app.route('/edit_profile', methods=['GET', 'POST'])
@login_required
def edit_profile():
    form = EditProfileForm()
    if form.validate_on_submit():
        current_user.username = form.username.data
        current_user.about_me = form.about_me.data
        db.session.commit()
        flash('Your changes have been saved.')
        return redirect(url_for('edit_profile'))
    elif request.method == 'GET':
        form.username.data = current_user.username
        form.about_me.data = current_user.about_me
    return render_template('edit_profile.html', title='Edit Profile',
                           form=form)

Эта функция просмотра несколько отличается от другой, обрабатывающей форму. Если validate_on_submit() возвращает True, я копирую данные из формы в объект пользователя, а затем записываю объект в базу данных. Но когда validate_on_submit() возвращает False, это может быть вызвано двумя разными причинами. Во-первых, это может быть связано с тем, что браузер просто отправил запрос GET, на который мне нужно ответить, предоставив исходную версию шаблона формы. Во-вторых, это также возможно в случае, когда браузер отправляет запрос POST с данными формы, но что-то в этих данных является недопустимым. Для этой формы мне нужно рассматривать эти два случая отдельно. Когда форма запрашивается в первый раз с запросом GET, я хочу предварительно заполнить поля данными, которые хранятся в базе данных, поэтому мне нужно сделать обратное тому, что я сделал в случае отправки, и переместить данные, хранящиеся в полях пользователя, в форму, поскольку это гарантирует, что эти поля формы имеют текущие данные, хранящиеся для пользователя. Но в случае ошибки проверки я не хочу ничего писать в поля формы, потому что они уже были заполнены WTForms. Чтобы различать эти два случая, я проверяю request.method, который будет GET для первоначального запроса, и POST для отправки, которая не прошла проверку.

Чтобы пользователи могли получить доступ к странице редактора профилей, следует добавить ссылку на страницу профиля:

            {% if user == current_user %}
            <p><a href="{{ url_for('edit_profile') }}">Edit your profile</a></p>
            {% endif %}

Обратите внимание на хитрый условный код, который я использую, чтобы убедиться, что ссылка «Редактировать» появляется, когда вы просматриваете свой собственный профиль, но не когда кто то просматриваете ваш. Или вы профиль кого-то другого.

<<< предыдущая следующая >>>

Как в Django определять админа, персонал, какую-то роль (которую определили в админке), как назначать свежезареганному пользователю роль?

Сразу прошу не ругаться и не кидать ссылки на https://docs.djangoproject.com/en/2.1/ref/contrib/auth/, ибо там не даются примеры простых действий, которые мне нужны и я не могу понять, что сделать чтобы получить результат.

Итак у меня есть пользователи:

  • admin - он же суперпользователь
  • personal - просто зарегистрированный пользователь с поставленной галочкой в админке напротив персонала.
  • manager - поставлена галочка персонала и добавлена роль manage (в которой разрешения на проверку заказов)
  • first, second, test, test2 ... - толпа пользователей, которым никакие права и роли не назначены (ибо я не знаю как это делать), но которые зарегистрированы не в админке, а в интернет-магазине при оформлении заказов и каждый из них может логиниться и каждый может заходить в свой ЛК

Да и вообще все перечисленные выше пользователи могут логиниться, оформлять заказы и заходить в свой ЛК.

Изначально планировалось создать серию админок-кабинетов под каждую роль. Но я с этим не могу разобраться уже неделю. Казалось бы простая вещь, но нигде в документации Django и в примерах на ютубе, даже англоязычном, я не могу найти простую вещь. (да, английский я не знаю и пользуюсь лишь гугл-переводчиком).

Что собственно мне нужно? А нужно в фале views.py простую вещь:

# если авторизован, то
    if request.user.is_authenticated:
         if это_суперпользователь:
                # загружаем админку-кабинет суперпользователя (тот который я сам сделал)
                # ...
          elif это_персонал без ролей:
                # загружаем админку-кабинет персонала (другой, но тот который я сам сделал) без каких-либо спец.разрешений
                # ...
          elif это_персонал с ролью manage:
                # загружаем админку-кабинет менеджера (другой, но тот который я сам сделал)
                # ...
          else: 
                # загружаем админку-кабинет простых пользователей (другой, но тот который я сам сделал)
                # ...  кстати это (надеюсь просто через подготовку данных и 
                # return HttpResponseRedirect(reverse('account'))   
                #  и объяснять мне не надо. Мне нужны именно что писать в If-ах?

Ну почему вот в такой простой доступной и понятной форме нельзя это написать в документации? Ребята ну помогите пожалуйста. Устал уже читать и смотреть кучу несвязанных отрывков.

И если не сложно, скажите что добавить в registration_view, чтобы назначить свежерегистрирующемуся определённую роль. Сейчас там так:

def registration_view(request):
    form = RegistrationForm(request.POST or None)

    if form.is_valid():
        new_user = form.save(commit=False)
        new_user.username = form.cleaned_data['username']
        new_user.set_password(form.cleaned_data['password']) 
        new_user.email = form.cleaned_data['email']
        new_user.first_name = form.cleaned_data['first_name']
        new_user.last_name = form.cleaned_data['last_name']
        new_user.save()

        login_user = authenticate(request, username=form.cleaned_data['username'], password=form.cleaned_data['password'])

        if login_user:
            login(request, login_user)
            return HttpResponseRedirect(reverse('account'))


    context = {
        'form': form,
    }
    return render(request, 'registration.html', context)

Готовый шаблон сайта с регистрацией, юзерами и админами на Flask с базами SQL или MongoDB


Бывает, приходится делать сайты на flask, у которых есть пользователи и админы. Чисто для себя решил как-то это стандартизировать и, главное, не терять время, когда такая задача появляется. Цель — в несколько команд получить рабочий сайт у которого есть:
  • Регистрация
  • Email подтверждение
  • Авторизация
  • Выход (logout)
  • Администраторы и роли администраторов
  • Административная, пользовательская и публичная часть сайта
  • Возможность юзера менять пароль
  • Восстановление пароля
  • Локализация для иностранных языков

Скриншоты


Вот что получается из коробки:

Профиль пользователя после авторизации:

Админка на flask-admin:

Получить такой сайт можно двумя вариантами:

I Вариант. С использованием flask-user и SQL-базы данных


Установка и запуск

Установка

cd ~
# Создаем виртуальное окружение
virtualenv env
# Активируем виртуальное окружение
. env/bin/activate
mkdir -p ~/www/my_app
cd www
git clone https://github.com/Alexmod/Flask-User-and-Flask-admin.git  my_app
cd my_app/
# Ставим необходимые модули
pip install -r requirements.txt
# Инициируем базу данных
python manage.py init_db
# Запускаем тесты
py.test tests/
# Если тесты успешно завершились, запускаем сервер
python manage.py runserver

После этих команд по адресу http://localhost:5000/ должен открыться сайт как на скриншотах.

Юзер: [email protected] Пароль: Password1.
Админ: [email protected] Пароль: Password1.

Я запускал и тестировал на linux с версией Python 3.4, но предполагаю, что должно «взлететь» и на любых 3.x.

Ссылка на GitHub.

Образец установки в консоле

Подробности первого варианта

Подробности


За основу я взял модуль Flask-User и вот этот репозиторий. Что было добавлено / изменено:
  1. Добавлена локализация как темплейтов, так и флэш-сообщений. Поддержка языков: (Немецкий, Английский, Испанский, Фарси, Финский, Французский, Итальянский, Датский, Русский, Шведский, Турецкий, Китайский). Если языка нет в списке, то по умолчанию в конфиге русский язык установлен в качестве дефолтного.
    # local_settings.py
    BABEL_DEFAULT_LOCALE = 'ru' 
    

    На русский язык я сделал свою локализацию.
    app/translations/ru/LC_MESSAGES/flask_user.po

    С flash-сообщениями отлично справился Flask-Babel, а вот чтобы в темплейтах заработал перевод на русский язык строк вида:
    {%trans%}Forgot your Password?{%endtrans%}
    или
    {{ _('Sign in') }}

    Пришлось поваландаться. Добавил:
    import gettext
    

    и вот такую функцию:
    def set_lang(lang):
        i18n_dir = app.config['BABEL_TRANSLATION_DIRECTORIES']
        gettext.install('lang', i18n_dir)
        trans_file = i18n_dir + lang + '/LC_MESSAGES/flask_user'
        tr = gettext.translation(trans_file, 'locale',  languages=[lang])
        tr.install(True)
        app.jinja_env.install_gettext_translations(tr)

  2. Удалил поля имени и фамилии при регистрации. По моему опыту это редко когда требуется, а юзеров раздражает.
  3. Все *.py файлы приведены к стандарту pep-8
  4. Вычищены модули, которые подгружаются, но не используются
  5. Роуты разбиты на 3 части: публичный, админский и пользовательский (public_view.py, members_views.py, про админку ниже)
  6. Добавлен модуль flask_bootstrap и вместе с ним изменены темплейты и показ flash-сообщений
    {% import "bootstrap/utils.html" as utils %} {{ utils.flashed_messages(dismissible=True, container=False) }}

    В файле layout.html.
  7. Добавил админку Flask-Admin (статья на хабре о ней). После нехитрых манипуляций она позволила активировать, деактивировать и удалять юзеров, дала возможность добавления ролей. Плюс работа со статическими файлами (загрузка на сервер, удаление, создание папок и т.д.). Пока без локализации.

    Дружить Flask-Admin и Flask-User не хотели при совместном использовании user_models.py.

    Пришлось для Flask-Admin создать отдельный файл models.py, и я так и не смог разобраться, почему они друг другу мешали.


II Вариант. С использованием flask-security и MongoDB

Скриншоты

Скриншоты


Вот что получается из коробки:


Установка и запуск

Установка

Надеюсь, что у вас уже установлен git, virtualenv и mongoDB.

cd ~
# Создаем виртуальное окружение
virtualenv env
# Активируем его
. env/bin/activate
# Создаем папку проекта
mkdir -p ~/www/my_app
cd www
git clone https://github.com/Alexmod/flask-security-flask-admin-mongodb.git  my_app
cd my_app
# Ставим все необходимые модули
pip install -r requirements.txt
# Запускаем сервер
python manage.py runserver

После этих команд по адресу http://localhost:5000/ должен открыться сайт как на скриншотах.

Юзер: [email protected] Пароль: Password1.
Админ: [email protected] Пароль: Password1.

Я запускал на linux с версией Python 3.6, но предполагаю, что должно «взлететь» и на любых 3.x.

Ссылка на GitHub для MongoDB

Деплой первого и второго варианта


Способов деплоя множество. Вот один самый простецкий.
Ставим gunicorn:
pip install gunicorn

В папке my_app создаем новый файл wsgi.py со следующим содержанием:
from app import create_app

app = create_app()

И запускаем:

gunicorn wsgi:app

Если все пройдет без ошибок, то по адресу http://127.0.0.1:8000 будет сайт, который можно прикручивать к nginx или apache. Дальше настраиваем systemd, чтобы он стартовал автоматически, и не забываем в файле local_settings.py изменить строку:

DEBUG = True # Меняем на False

Погружение в шаблоны и приручение GPO Windows / Сервер Молл corporate blog / Habr

В очередной статье из цикла «конспект админа» мне хотелось бы освежить в памяти несколько нюансов использования групповых политик. Заодно поразвлекаемся с созданием своих шаблонов и с автоматизацией работы с этими самыми политиками.


Я не буду рассказывать, что такое групповые политики, и остановлюсь лишь на основных моментах, которые стоит иметь в виду при работе с ними.

В системах Windows помимо доменных существуют и локальные групповые политики ― управлять ими можно при помощи оснастки gpedit.msc на системах редакции Professional и выше. Часто считается, что без домена можно настраивать локальные групповые политики только для всех пользователей на компьютере. Это не совсем верно ― с выходом Windows Vista появилась возможность использовать множественную локальную групповую политику или MLGPO. Этот механизм позволяет настраивать отдельные политики для разных пользователей.

Добраться до него можно через вызов консоли mmc: при добавлении оснастки «Управление объектами групповой политики» нажать кнопку «Обзор». Далее на вкладке «Пользователи» уже можно выбрать конкретного пользователя или группу «Администраторы» и «Не администраторы». К сожалению, управление для группы пользователей не реализовано.


Управление групповой политикой для отдельных пользователей.


Бывало и так, что на отдельностоящем терминальном сервере разворачивали Active Directory только для того, чтобы отдельному пользователю настроить поведение драйвера для EasyPrint. Не надо так.

При добавлении доменных групповых политик стоит помнить про порядок их применения ― политика, примененная последней, будет обладать наивысшим приоритетом (да и на собеседованиях часто спрашивают).

Итак, предположим, что у нас есть компьютер в домене и четыре групповые политики: локальная на этом компьютере; политика на подразделение, в котором находится компьютер; политика на домен и политика на лес. Порядок их применения будет следующим:


  1. Локальная групповая политика.
  2. Групповая политика сайта.
  3. Групповая политика домена.
  4. Групповая политика верхнего подразделения.
  5. Групповая политика дочернего подразделения.

То есть чем ближе к объекту, тем приоритетнее, за исключением локальной групповой политики. Если надо отключить применение вышестоящих политик, то ставьте блокировку наследования.


Блокировка наследования.

Любую групповую политику можно условно разделить на две конфигурации ― пользователя и компьютера. Обычно политики с настройками компьютеров назначаются на подразделение, в котором находятся компьютеры. А политики с настройками пользователей ― на пользователей.

Если надо применить настройки компьютера к подразделению с пользователями и наоборот, используют так называемое замыкание групповой политики. Например, такая настройка пригодится, когда нужно применить специфические политики к пользователям для работы на терминальных серверах.

Работа замыкания настраивается непосредственно в политике ― «Настройка компьютера ― Административные шаблоны ― Система ― Режим обработки замыкания пользовательской групповой политики». Подробнее про механизм уже писали в статье про использование Merge\Replace в GPO. Я лишь добавлю, что режим замыкания групповой политики ― тоже частый вопрос на собеседовании.


Настройка замыкания групповой политики.

Физически доменные групповые политики находятся в папке SYSVOL на контроллерах домена. Папка реплицируется между контроллерами. Каждая групповая политика выглядит как папка с именем в виде GUID.


Групповые политики домена.

Правила фильтрации, настраиваемые через редактор групповой политики, соответствуют настройкам прав NTFS на соответствующую подпапку.


Говоря о правилах фильтрации, нельзя не упомянуть обновление MS16-072, которое «сломало» групповые политики. Теперь для того чтобы работали правила фильтрации, надо добавлять к каждому фильтру правило «на чтение», но не «на применение» группе Domain Computers.

В каждой папке с групповой политикой существуют подпапки Machine и User, соответствующие настройкам пользователя и компьютера. Если углубиться в подпапки, можно легко понять структуру групповой политики:


  • В корне папки находится файл GPT.ini с настройками групповой политики, такими как ее название.
  • В подпапках Machine и User сидят файлы registry.pol с настройками соответствующих веток реестра.
  • По пути Microsoft\Windows NT\SecEdit можно найти шаблон настроек безопасности ― GptTmpl.inf.
  • В подпапке Preferences находятся предпочтения групповых политик, представляющие из себя подпапки с файлами xml.
  • В подпапке Applications сидят дистрибутивы для развертывания через групповые политики.
  • В папке Scripts находятся скрипты на logon\logoff для пользователя и startup\shutdown для компьютера.
  • В папке Documents and Settings есть настройки перенаправления пользовательских папок.
  • Наконец, в папке Adm находятся устаревшие шаблоны групповой политики.

Подробнее про структуру можно почитать в материале Group Policy Basics, поэтому перейдем сразу к шаблонам.


По сути своей административные шаблоны ― это специальные файлы с инструкциями по изменению клиентского реестра (ветки HKCU или HKLM) и настройками отображения изменяемых параметров через «Управление групповой политикой». В принципе, реестр можно менять и через «Предпочтения групповых политик». Но разница здесь не только в красивом интерфейсе.


Способ изменения реестра Как ведет себя при удалении политики со стандартными настройками Можно ли изменить параметр вручную Можно ли изменить параметр через приложение
Шаблоны Параметр реестра восстанавливается на значение «по умолчанию», если настройки по умолчанию есть в шаблоне - -
Предпочтения политик Параметр реестра не изменяется + +

Сравнение предпочтения групповых политик и административных шаблонов.

Другими словами, настройка реестра через шаблоны групповых политик более строгая. Тогда как настройка через предпочтения групповых политик напоминает периодическое применение reg-файла. Конечно, предпочтения позволяют не только менять параметры реестра, но и довольно гибко настраиваются. Тем и ценны.


Это актуально при изменении ветки Policies, и настраиваемое приложение должно хранить свои настройки в реестре. Простое изменение параметров через Предпочтения и Шаблоны будет работать схожим образом, только шаблоны могут оказаться удобнее.

До появления Windows Vista\2008 в качестве шаблона групповых политик брали исключительно стандарт .adm. Будучи с простой структурой, которую было легко редактировать вручную, этот стандарт обладал и рядом недостатков:


  • Для каждого языка приходилось создавать отдельный файл шаблона.
  • Файл шаблона физически находился в папке с групповой политикой. При использовании одного и того же шаблона он сохранялся в каждую папку, что увеличивало занимаемое место и время репликации.
  • Не поддерживались мультистроковые параметры и параметры QWORD.

На замену устаревшему стандарту появился новый. Новые шаблоны представляют собой два файла: сам шаблон, не зависимый от языка ― .admx и языковой «пакет» к нему ― файл .adml. Теперь шаблоны можно «положить» в центральное хранилище, и обращаться к нему, не плодя одинаковые файлы в папке SYSVOL.

Не обошлось без ложки дегтя ― теперь содержимое файла представляет собой популярный в индустрии формат XML. И создавать новые шаблоны в блокноте стало уже не так удобно.

Под большинство параметров, которые могут понадобиться, шаблоны уже существуют. Кроме того, многие производители приложений выпускают свои административные шаблоны. Вот несколько примеров:


Если возникает необходимость разработать и внедрить свой административный шаблон, то самый простой вариант ― это создать старый файл .adm и сконвертировать его в admx специальной утилитой. Вариант посложнее ― начинать сразу с .admx.


Для начала разберем простой пример. Создадим шаблон групповой политики, который позволит нам включать и выключать отображение скрытых и системных файлов, а заодно и отображение расширений.


Сразу скажу, что это можно провернуть через «Предпочтения групповых политик» ― в параметрах панели управления ― опции папки. Но мы легких путей не ищем и заодно не хотим, чтобы параметры отображения можно было менять вручную.

За необходимые нам параметры отвечают три ключа в реестре:


  • Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Hidden.
  • Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\HideFileExt.
  • Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ShowSuperHidden.

Содержимое ADM-шаблона, который разберем далее, под спойлером.
CLASS USER
CATEGORY !!ShowExplorer
    POLICY !!ShowHiddenFiles
        KEYNAME "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
        EXPLAIN !!ShowHiddenFilesExplanation
        VALUENAME "Hidden"
        VALUEON NUMERIC "1"
        VALUEOFF NUMERIC "2"
    END POLICY

    POLICY !!ShowFileExtensions
        KEYNAME "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
        EXPLAIN !!ShowFileExtensionsExplanation
        VALUENAME "HideFileExt"
        VALUEON NUMERIC "0"
        VALUEOFF NUMERIC "1"
    END POLICY

    POLICY !!ShowSuperHiddenFiles
        KEYNAME "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
        EXPLAIN !!ShowSuperHiddenFilesExplanation
        VALUENAME "ShowSuperHidden"
        VALUEON NUMERIC "1"
        VALUEOFF NUMERIC "0"
    END POLICY
END CATEGORY

[strings]
ShowExplorer="Отображение файлов в проводнике"
ShowHiddenFiles="Показывать скрытые файлы"
ShowHiddenFilesExplanation="Когда эта настройка включена, проводник будет показывать скрытые файлы."
ShowSuperHiddenFiles="Показывать системные файлы"
ShowSuperHiddenFilesExplanation="Когда эта настройка включена, проводник будет показывать системные файлы"
ShowFileExtensions="Показывать расширения файлов"
ShowFileExtensionsExplanation="Когда эта настройка включена, проводник будет показывать расширения файлов"

Разберем подробнее синтаксис файла.


  • CLASS. Может принимать значение USER или MACHINE ― в зависимости от класса будет изменятся ветка реестра HKCU или HKLM соответственно.
  • CATEGORY. Строка, в которой задается имя «папки» политики.
  • POLICY. В строке задается название конкретной политики ― у нас таких будет три.
  • KEYNAME. Путь в реестре к изменяемым параметрам.
  • EXPLAIN. Отсылка к «переменной» с объяснением настройки.
  • VALUENAME. Название изменяемого параметра в реестре.
  • VALUEON**VALUEOFF**. Значение, которое будет принимать параметр при включении и выключении его в политике.
  • [strings]. Секция со значениями переменных, которые я использовал для текстовых строк. Можно их не использовать, но тогда могут быть проблемы из-за русского языка.

Помимо задействованных опций есть и другие, например:


  • EDITTEXT. Текстовое поле для ввода.
  • NUMERIC. Поле для ввода цифр.
  • CHECKBOX. Список, где можно отмечать параметры «галочками».
  • COMBOBOX. Список с «переключателем»
  • DROPDOWNLIST. Выпадающий список.
  • LISTBOX. Список для ввода нескольких элементов.

Подробнее со всеми параметрами можно ознакомится в разделе MSDN ADM Format.

Установить новый шаблон не просто, а очень просто ― достаточно щелкнуть правой кнопкой мыши по пункту «Административные шаблоны», выбрать «Добавление и удаление шаблонов» и добавить наш свежесозданный шаблон.


Добавленный шаблон.

После установки шаблона он отобразится в ветке «Классические административные шаблоны».

Теперь можно сконвертировать наш шаблон в .admx с помощью утилиты faAdmxConv из ADMX Migrator.


Конвертируем шаблон.

После конвертации получившийся шаблон .admx и папку Ru-ru с файлом локализации .adml нужно скопировать в папку %Systemroot%\PolicyDefinitions для локальной политики или в папку Sysvol\PolicyDefinitions на контроллере домена.


Установленный шаблон .admx.


Полный листинг получившегося шаблона и файла локализации под спойлером.

Шаблон:

<?xml version="1.0" encoding="utf-8"?>
<policyDefinitions revision="1.0" schemaVersion="1.0">
  <policyNamespaces>
    <target prefix="fullarmor" namespace="FullArmor.6fb075d6-ddee-4302-9d06-50c4d83e1910" />
    <using prefix="windows" namespace="Microsoft.Policies.Windows" />
  </policyNamespaces>
  <supersededAdm fileName="E:\1\explorer.adm" />
  <resources minRequiredRevision="1.0" />
  <supportedOn>
    <definitions>
      <definition name="SUPPORTED_NotSpecified" displayName="$(string.ADMXMigrator_NoSupportedOn)" />
    </definitions>
  </supportedOn>
  <categories>
    <category name="ShowExplorer" displayName="$(string.ShowExplorer)" />
  </categories>
  <policies>
    <policy name="ShowHiddenFiles" displayName="$(string.ShowHiddenFiles)" explainText="$(string.ShowHiddenFilesExplanation)" presentation="$(presentation.ShowHiddenFiles)" key="Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" valueName="Hidden">
      <parentCategory ref="ShowExplorer" />
      <supportedOn ref="SUPPORTED_NotSpecified" />
      <enabledValue>
        <decimal value="1" />
      </enabledValue>
      <disabledValue>
        <decimal value="2" />
      </disabledValue>
    </policy>
    <policy name="ShowFileExtensions" displayName="$(string.ShowFileExtensions)" explainText="$(string.ShowFileExtensionsExplanation)" presentation="$(presentation.ShowFileExtensions)" key="Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" valueName="HideFileExt">
      <parentCategory ref="ShowExplorer" />
      <supportedOn ref="SUPPORTED_NotSpecified" />
      <enabledValue>
        <decimal value="0" />
      </enabledValue>
      <disabledValue>
        <decimal value="1" />
      </disabledValue>
    </policy>
    <policy name="ShowSuperHiddenFiles" displayName="$(string.ShowSuperHiddenFiles)" explainText="$(string.ShowSuperHiddenFilesExplanation)" presentation="$(presentation.ShowSuperHiddenFiles)" key="Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" valueName="ShowSuperHidden">
      <parentCategory ref="ShowExplorer" />
      <supportedOn ref="SUPPORTED_NotSpecified" />
      <enabledValue>
        <decimal value="1" />
      </enabledValue>
      <disabledValue>
        <decimal value="0" />
      </disabledValue>
    </policy>
  </policies>
</policyDefinitions>

Файл локализации:

<?xml version="1.0" encoding="utf-8"?>
<policyDefinitionResources revision="1.0" schemaVersion="1.0">
  <displayName></displayName>
  <description></description>
  <resources>
    <stringTable>
      <string>Отображение файлов в проводнике</string>
      <string>Показывать скрытые файлы</string>
      <string>Когда эта настройка включена, проводник будет показывать скрытые файлы.</string>
      <string>Показывать системные файлы</string>
      <string>Когда эта настройка включена, проводник будет показывать системные файлы</string>
      <string>Показывать расширения файлов</string>
      <string>Когда эта настройка включена, проводник будет показывать расширения файлов</string>
      <string>ADMX Migrator encountered a string that is not present in the source ADM string table.</string>
      <string>ADMX Migrator encountered a policy that does not have a supportedOn value.</string>
    </stringTable>
    <presentationTable>
      <presentation />
      <presentation />
      <presentation />
    </presentationTable>
  </resources>
</policyDefinitionResources>

Действительно, xml в новом формате читается чуть хуже, чем старый .adm. Для облегчения работы с новым форматом в поставке ADMX Migrator есть утилита faAdmxEditor.msc. Помимо этой утилиты есть и скрипты для конвертации reg-файлов в шаблоны, и сторонние платные утилиты.

Конечно же, можно обойтись без вот-этого-всего и разобраться самостоятельно ― оставлю это в качестве домашнего задания. Благо на портале MSDN есть подробное описание XML-схемы, и есть неплохие материалы с примерами в сети. Например, «Административные шаблоны групповой политики».

Теперь перейдем к автоматизации.


Работать с групповыми политиками из командной строки довольно тоскливо. Основных инструментов можно выделить три.

PowerShell. Есть набор командлетов для резервного копирования, восстановления и управления групповыми политиками. Создание новых политик ограничено ― можно лишь изменять реестр. Впрочем, в большинстве случаев и этого достаточно. В качестве примера создадим групповую политику, которая отключит автоматическое обновление Adobe Reader DC.

За отключение автоматического обновления отвечает ключ реестра bUpdater в ветке [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Adobe\Acrobat Reader\DC\FeatureLockDown]. Установив параметр в 0, мы отключим опцию.

Создание групповой политики на PowerShell будет выглядеть так:

Import-module -Name GroupPolicy
Write-Host "Создаем новый объект политики с именем Adobe_Reader_disable_autoupdate"
New-GPO -Name Adobe_Reader_disable_autoupdate
Write-Host "Добавляем нужное нам значение реестра"
Set-GPRegistryValue -Name "Adobe_Reader_disable_autoupdate" -key "HKLM\SOFTWARE\Policies\Adobe\Acrobat Reader\DC\FeatureLockDown" -ValueName  bUpdater -TypeDWord -value 0
Write-Host "Прилинковываем новый объект к нужному OU"
Set-GPLink -Name Adobe_Reader_disable_autoupdate -Target "ou=Computers,dc=domain,dc=com" -LinkEnabled Yes

Свежесозданная групповая политика.

Полный список и описание командлетов доступны в материале Technet Group Policy Cmdlets in Windows PowerShell.

Интерфейс COM к GPMC (консоли управления групповой политикой). Способ позволяет сделать с политиками многое, на любом языке программирования, поддерживающим COM-интерфейсы. К сожалению, популярность он не приобрел и примеров в сети довольно мало, несмотря на богатое описание методов интерфейса на портале MSDN. Немногочисленные примеры использования доступны для загрузки в галерее Technet.

LGPO.exe. Не так давно Microsoft заменил набор утилит для работы с локальными групповыми политиками на единую утилиту. Скачать ее можно на официальном сайте. Утилита удобна для копирования и развертывания локальных групповых политик. Заявлена и поддержка MLGPO. Создавать свои политики тоже можно. Также программа удобна для создания и изменения файлов реестра registry.pol. Для примера изменим локальную групповую политику, добавив в нее отключение обновления несчастного Acrobat Reader DC.

Сделаем бэкап локальной групповой политики командой

lgpo.exe /b C:\Temp /n "Backup"

В папке C:\Temp появится подпапка с GUID по структуре схожая с доменными групповыми политиками:

Теперь развернем registry.pol в текстовый файл:

LGPO.exe /parse /m C:\temp\{GUID}\DomainSysvol\GPO\Machine\registry.pol >> reg.txt

Синтаксис текстового файла очевиден. Добавим в него значения реестра для отключения автоматического обновления «Акробата»:


Добавленный в файл параметр реестра.

Теперь останется завернуть наш reg.txt обратно в registry.pol и импортировать изменившийся файл обратно в локальную групповую политику:

LGPO.exe /r C:\Temp\reg.txt /w C:\Temp\registry.pol
LGPO.exe /m C:\Temp\registry.pol​

Все эти махинации, конечно же, можно завернуть в один скрипт и использовать для массового изменения локальной групповой политики привычным инструментом для запуска команд на удаленных компьютерах. Подробнее про методы запуска команд можно почитать в нашей статье «1000++ способ запуска команд на удаленном компьютере».

Конечно же, зная структуру доменной групповой политики, ничто не мешает сделать удобный именно вам инструмент для создания и управления политиками. Поделитесь в комментариях, есть ли у вас свои способы настройки реестров пользовательских машин?

Экстраполя на Cotonti для профиля пользователя. - Статьи пользователей

Экстраполя для профиля пользователя.

  (2)

Опубликовано в: Статьи пользователей 01.01.1970 29.12.2017

Создание дополнительных полей для профиля пользователя на сайте фриланс-биржи на Cotonti. Экстраполя.

Очень часто при работе с сайтом на Cotonti возникает задача создания дополнительных полей для заполнения пользователями в своем профиле. Принцип работы с экстраполями.

Допустим, перед нами стоит задача создать поля: Название компании, Адрес, Телефон.

1) Для начала надо уяснить для себя, что в Cotonti данные пользователей хранятся в таблице базы данных, которая называется cot_users (Префикс cot_ может быть другим. например во фриланс-бирже префикс по-умолчанию имеет значение flance_). Чтобы создать экстраполе для этой таблицы, нам нужно перейти в админке в раздел Экстраполя и выбрать нашу таблицу.

2) На странице будет выводиться форма создания экстраполя, а также список уже созданных экстраполей (если они уже были созданы ранее). Итак, чтобы создать экстраполе нам понадобится выбрать для них код и название. Код экстраполя должен состоять только из латинских символов, а название может быть написано на русском.

В нашем случае мы определим значения таким образом:

company - Название компании
addr - Адрес
phone - Телефон

Также для экстраполя можно установить тип поля и другие значения, если например поле будет в виде селекта или другого множественного элемента веб-формы. По-умолчанию тип поля устанавливается в виде простого инпута.

3) После того как мы создали наши экстраполя, нам необходимо разместить их в соответствующих шаблонах пользователя: профиль (users.profile.tpl) и страница пользователя (users.details.tpl).

В профиле пользователь может редактировать свои данные, то есть этот шаблон (users.profile.tpl) содержит форму. Форматы тэгов в ней имеют такой вид: {USERS_PROFILE_НАЗВАНИЕПОЛЯ}

В нашем случае в этот шаблон нужно прописать такие тэги:

Поле "Название компании":
{USERS_PROFILE_COMPANY} - само поле
{USERS_PROFILE_COMPANY_TITLE} - название поля

Поле "Адрес":
{USERS_PROFILE_ADDR} - само поле
{USERS_PROFILE_ADDR_TITLE} - название поля

Поле "Телефон":
{USERS_PROFILE_PHONE} - само поле
{USERS_PROFILE_PHONE_TITLE} - название поля

 

Аналогичным образом прописываются значения этих полей на странице пользователя для вывода информации, но формат тэгов уже должен быть иным {USERS_DETAILS_НАЗВАНИЕПОЛЯ}:

Поле "Название компании":
{USERS_DETAILS_COMPANY} - значение поля
{USERS_DETAILS_COMPANY_TITLE} - название поля

Поле "Адрес":
{USERS_DETAILS_ADDR} - значение поля
{USERS_DETAILS_ADDR_TITLE} - название поля

Поле "Телефон":
{USERS_DETAILS_PHONE} - значение поля
{USERS_DETAILS_PHONE_TITLE} - название поля

Для шаблона users.edit.tpl:

Поле "Название компании":
{USERS_EDIT_COMPANY} - значение поля
{USERS_EDIT_COMPANY_TITLE} - название поля

Поле "Адрес":
{USERS_EDIT_ADDR} - значение поля
{USERS_EDIT_ADDR_TITLE} - название поля

Поле "Телефон":
{USERS_EDIT_PHONE} - значение поля
{USERS_EDIT_PHONE_TITLE} - название поля

 

Обратите внимание, для каждого раздела в Cotonti структура тэгов экстраполей имеет разный формат. Чтобы определить этот формат, рекомендуется смотреть шаблоны соответствующих разделов.

------ Cotonti plugins ------

Нужна помощь и поддержка ? в установке и настройке плагинов для фриланс-биржи на Cotonti ???жмите тут!

------ Cotonti plugins ------

как настроить, подводные камни и фишки

Форма сбора заявок ВКонтакте (она же лид-форма) — приложение для сообществ, которое позволяет собирать заявки клиентов прямо в социальной сети. Это сокращает путь до пользователя: если он решил воспользоваться вашим предложением, он сразу отдаст вам свои данные, и точно не потеряется по пути из соцсети на ваш сайт.  

Форму можно настраивать под разные цели: сбор коммерческих заявок, подписку на рассылку, регистрацию на вебинар и т.д. 

В этой статье мы покажем, как создать лид-форму в ВК, запустить ее на рекламу, превратить форму в обратный звонок и куда не нужно нажимать, чтобы не потерять несохраненные изменения (а то и всю форму).

Как создать лид-форму: руководство по каждому полю

Форму можно создать двумя путями:

  • в настройках сообщества (через Управление — Приложения),
  • в рекламном кабинете (после выбора цели «Сбор заявок»). 

В целом механика не отличается друг от друга, поэтому мы рассмотрим только первый вариант. 

Добавьте приложение

Перейдите в раздел Управление — Приложения

Откройте страницу сообщества, в правом меню выберите блок «Управление». В правом меню открывшейся страницы нажмите «Приложения» и найдите форму сбора заявок. Перейдите в настройки приложения.

Заголовок и описание

Этот блок отвечает за то, согласится ли пользователь оставить вам свои контакты. В нем вы дополнительно объясняете, что вы предлагаете и зачем пользователю это нужно. 

Первый редактируемый блок — название формы. Он будет виден только вам, в рекламном кабинете или настройках приложения. По умолчанию в него проставляется дата создания. Чтобы изменить название, нажмите на него.

Заголовок: еще раз скажите пользователю, для чего он заполняет эту форму. «Регистрация на вебинар», «Запись на прием» и т.д.

Описание: расскажите, что получит пользователь. Если это вебинар — о чем он будет, если услуга — что в нее входит, если товар — как он выглядит, когда вы его доставите и т.д.

В отличие от лид-формы Facebook, здесь нет встроенного редактора, форматирование текста нужно прописывать вручную с помощью wiki-разметки. Это несложно, если знать нужные тэги. 

Основные: 

  • жирный — <b>текст</b>,
  • курсив — <i>текст</i>,
  • зачеркнуть — <s>текст</s>,
  • подчеркнуть — <u>текст</u>,
  • маркированный список — *текст (так нужно оформлять каждый пункт списка). Если у списка несколько уровней, то чем ниже уровень, тем больше звездочек нужно ставить: ** (второй), *** (третий).
  • нумерованный список — #текст (оформляется по аналогии с маркированным). 

Вопросы

Укажите, какие данные собирать с пользователя. По умолчанию форма запрашивает только имя, а с этой информацией трудно что-то сделать. 

Среди стандартных полей с автозаполнением есть только два — телефон и email. Для них предусмотрена кнопка «Изменить» — если пользователь нажмет ее, он сможет ввести другие данные.

В некоторых формах специалисты отказываются от автозаполнения в принципе (через функцию «Добавить свой вопрос»). Это важно, если вы хотите собирать максимально валидные лиды. Например, при сборе регистраций на вебинар об этом можно не беспокоиться, а вот если вы собираете заявки на автобусный тур с ограниченным количеством мест — «случайные» заявки могут быть критичными.
Форма для сбора лидов может обрабатывать 8 стандартных вопросов и 5 пользовательскихФорма для сбора лидов может обрабатывать 8 стандартных вопросов и 5 пользовательских

Не злоупотребляйте вопросами. Запрашивайте только ту информацию, которая действительно необходима вам для обработки заявки. Не пытайтесь выяснить о пользователе все данные, ведь чем больше вопросов, тем меньше вероятность, что человек заполнит форму до конца. Помните, вам не нужен его размер обуви, если это не форма заказа сапог.  

Политика конфиденциальности

Любая компания, которая собирает, обрабатывает и хранит персональные данные, должна иметь политику конфиденциальности. Укажите ссылку на документ, пользователь сможет перейти на него по гиперссылке в подвале формы.

Подтверждение

Это второй экран формы — благодарность за отправку. По умолчанию в ней установлен такой текст:

В блоке описание действует та же вики-разметка, что и в первом блоке.

Настройки

Что здесь есть:

  • Запретить повторное заполнение формы — мы советуем включать ее во всех случаях, если в форме не подразумевается несколько заполнений.
  • Уведомлять о новых заявках в личные сообщения — тут можно выбрать одного или нескольких администраторов страницы, которые будут получать уведомления.
  • Уведомлять о новых заявках через email — введите электронный адрес (или несколько адресов), на который нужно отправлять уведомления. 

И вот он, подводный камень. Последний пункт формы, который легко может сломать все — пиксель ВКонтакте. 

Он нужен, чтобы автоматически собирать всех, кто открыл форму, в аудиторию для ретаргетинга (в рекламном кабинете). Подробнее о том, как установить пиксель на свой сайт и добавить в форму, читайте в инструкции. Сам ввод кода пикселя ничего не сломает. Но если вы решите перейти по ссылке из всплывающей подсказки (знак вопроса), новая страница откроется в этом же окне, обнулив все изменения. Форму вы восстановить не сможете, придется создавать ее заново. Кстати, с нашей формой из примера именно это и произошло 🙃
Осторожнее с гиперссылками внутри формы: они могут сбросить все измененияОсторожнее с гиперссылками внутри формы: они могут сбросить все изменения

Когда вы заполните все нужные вам поля, сохраните форму в правом верхнем углу редактора.

Запускаем форму на рекламу: цель, пост и кнопка

Перейдите в рекламный кабинет ВКонтакте. При создании нового объявления выберите цель «Сбор заявок».

Цель сбор заявок ВКонтакте отвечает за рекламу формы. Выберите ееЦель сбор заявок ВКонтакте отвечает за рекламу формы. Выберите ее
Затем выберите форму, которую вы создали, и нажмите «Создать объявление». Оно выглядит как обычная запись ВКонтакте. Напишите подводку к форме, добавьте изображение (ВК просит картинку размером 537х240 рх, но мы делаем в четыре раза больше — 2148х960 px, чтобы качество изображения не терялось).

Теперь настройте аудиторию и сохраните объявление. Смените его статус на «Запущено». Объявление запустится автоматически после одобрения модератора.

2 способа выгрузить собранные лиды

Вы можете выгрузить лиды прямо из ВКонтакте, они хранятся в том же разделе, где вы создавали форму (Управление — Приложения — Перейти к настройкам в приложении).

Что с этим способом не так? Заявки очень быстро «протухают» (если это не регистрации на вебинар, конечно). Это значит, что чем раньше вы или ваш отдел продаж заявку обработает, тем выше вероятность, что клиент действительно что-то купит. Поэтому выгружать файл даже раз в день может быть слишком долго, а вручную передавать данные из уведомлений (мы их настраивали на последнем шаге формы) — муторно и долго. Мы ведь ждем много заявок, правда?

Поэтому есть второй вариант — настроить синхронизацию формы с вашей CRM, данные будут автоматически передаваться в нее. Для этого нужно настроить синхронизацию через API. 

Перейдите в раздел Управление на странице своего сообщества, а затем в раздел Работа с API — Callback API. Попросите своих разработчиков настроить синхронизацию с помощью документации ВКонтакте. На последнем этапе во вкладке «Типы событий» нужно поставить галочку в чек-боксе «Lead forms: Новая заявка». 

Но не все обращения одинаково полезны, а в CRM обычно хранят уже проверенные лиды. Чтобы не засорять лист контактов, можно настроить передачу заявок в другую систему учета обращений (в современных онлайн-чатах и коллтрекингах обычно есть этот функционал), и только потом передавать действительно целевые лиды в CRM.

В столбце «Класс» менеджеры указывают качество обращения. Заявки с классом Лид автоматически передаются в CRM. 

Также из формы подгружается имя и известные контактные данные пользователя, название формы, текст заявки и запись обратного звонка (если настроено). Записи можно прослушать в течение 40 дней.

Как превратить форму сбора заявок в обратный звонок

Это можно сделать только при помощи синхронизации ВКонтакте и обратного звонка стороннего сервиса, причем того, кто эту возможность поддерживает. МультиЧат Callibri да.

Как это сделать: 

  1. Настроить синхронизацию ВК и Callibri через Callback API.
  2. В разделе «Типы событий» поставить галочку на «Lead forms: Новая заявка». 
  3. Создать форму сбора заявок и в разделе вопросы оставить только номер телефона. Заполнить остальные разделы формы.
  4. Перейти в рекламный кабинет, создать рекламное объявление с целью «Сбор заявок», запустить объявление. 
Что будет происходить? Когда пользователь заполнит поле с номером и нажмет кнопку «Отправить», запустится система обратного звонка: Callibri сделает дозвон вашему менеджеру, а когда он примет звонок — наберет указанный клиентом номер. С точки зрения пользователя это будет выглядеть как обычный входящий звонок. Запись разговора и все данные о коммуникации (имя, фамилия, откуда пришла заявка и т.д.) сохранится в ЕЖЛ.Попробовать Callibri

Советы, которые нужно запомнить

  • Не ленитесь заполнять все разделы, даже те, которые помечены как необязательные. Экран благодарности — это важно.
  • Если изменения еще не сохранены, переходите по ссылкам в подсказках только с помощью функции «открыть в новом окне» (вызывается кликом правой кнопки мыши). Иначе все, что вы создавали несколько минут или часов, может безвозвратно испариться. 
  • Чтобы качество изображения в рекламном объявлении не снижалось, загружайте картинки размером в четыре раза больше требуемого — 2148х960 px.
  • С помощью синхронизации ВКонтакте со сторонними сервисами (CRM, онлайн-чат, коллтрекинг) вы сможете максимально быстро обработать поступившие заявки — менеджеры увидят их в режиме реального времени, а не когда маркетолог решит выгрузить файл. 
  • Callibri может превратить форму сбора заявок ВКонтакте в обратный звонок. 
Тестируйте!

Хотите узнать больше об инструментах интернет-маркетинга? Подпишитесь на еженедельный дайджест Callibri. В нем мы собираем полезные статьи и вебинары, выходит по вторникам. Форма подписки справа 👉

Советуем прочитать

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *