Projet

Général

Profil

0001-manager-add-help-on-users-imports-34238.patch

Benjamin Dauvergne, 25 juin 2019 12:37

Télécharger (11 ko)

Voir les différences:

Subject: [PATCH] manager: add help on users imports (#34238)

 src/authentic2/attribute_kinds.py             |   1 +
 .../static/authentic2/manager/css/style.css   |   8 +
 .../authentic2/manager/user_imports.html      | 175 +++++++++++++++---
 src/authentic2/manager/user_views.py          |  36 ++++
 4 files changed, 197 insertions(+), 23 deletions(-)
src/authentic2/attribute_kinds.py
244 244
        },
245 245
        'html_value': profile_image_html_value,
246 246
        'attributes_ng_serialize': profile_attributes_ng_serialize,
247
        'csv_importable': False,
247 248
    },
248 249
]
249 250

  
src/authentic2/manager/static/authentic2/manager/css/style.css
52 52
.email, #user-table .first_name, #user-table .last_name, #user-table .ou {
53 53
        text-align: left;
54 54
}
55
table.main.left {
56
	padding-left: 1rem;
57
}
58
table.main.left td,
59
table.main.left th {
60
	text-align: left;
61
}
62

  
55 63
table.feeds td.url {
56 64
	text-align: left;
57 65
	padding-left: 1em;
src/authentic2/manager/templates/authentic2/manager/user_imports.html
21 21
{% endblock %}
22 22

  
23 23
{% block content %}
24
  <h3>{% trans "Imports" %}</h3>
25
  <table class="main">
26
    <thead>
27
      <tr>
28
        <th>{% trans "Filename" %}</th>
29
        <th>{% trans "Creation date" %}</th>
30
        <th>{% trans "By" %}</th>
31
        <th>{% trans "Rows" %}</th>
32
        <th></th>
33
      </tr>
34
    </thead>
35
    <tbody>
36
      {% for import in imports %}
37
        <tr>
38
          <td><a href="{% url "a2-manager-users-import" uuid=import.uuid %}">{{ import.filename }}</a></td>
39
          <td>{{ import.created }}</td>
40
          <td>{{ import.user }}</td>
41
          <td>{{ import.rows_count }}</td>
42
          <td><form method="post">{% csrf_token %}<button name="delete" value="{{ import.uuid }}">{% trans "Delete" %}</button></form></td>
43
        </tr>
44
      {% endfor %}
45
    </tbody>
46
  </table>
24
  <div class="section">
25
    <h3>{% trans "Imports" %}</h3>
26
    <table class="main left">
27
      <thead>
28
        <tr>
29
          <th>{% trans "Filename" %}</th>
30
          <th>{% trans "Creation date" %}</th>
31
          <th>{% trans "By" %}</th>
32
          <th>{% trans "Rows" %}</th>
33
          <th></th>
34
        </tr>
35
      </thead>
36
      <tbody>
37
        {% for import in imports %}
38
          <tr data-uuid="{{ import.uuid }}">
39
            <td><a href="{% url "a2-manager-users-import" uuid=import.uuid %}">{{ import.filename }}</a></td>
40
            <td>{{ import.created }}</td>
41
            <td>{{ import.user }}</td>
42
            <td>{{ import.rows_count }}</td>
43
            <td><form method="post">{% csrf_token %}<button name="delete" value="{{ import.uuid }}">{% trans "Delete" %}</button></form></td>
44
          </tr>
45
        {% endfor %}
46
      </tbody>
47
    </table>
48
  </div>
49

  
50
  <div class="section">
51
    <h3>{% trans "Help" %}</h3>
52
    <p>
53
      {% blocktrans trimmed %}
54
        The first line of your CSV file must be a header <a href="#help-attributes">mapping columns to user's attributes identifier</a>.
55
        Each user attribute name can be followed by <a href="#help-flags">flags</a> separated by spaces.
56
        You can also import an <a href="#help-external-identifier">external identifier</a> to prevent creating duplicates when doing multiple import from the same source.
57
      {% endblocktrans %}
58
    </p>
59
    <h4 id="help-attributes">{% trans "Attributes" %}</h4>
60
    <table class="main left">
61
      <thead>
62
        <tr>
63
          <th>{% trans "Label" %}</th>
64
          <th>{% trans "Identifier" %}</th>
65
        </tr>
66
      </thead>
67
      <tbody>
68
        {% for column in help_columns %}
69
          <tr>
70
            <td>{{ column.label }}</td>
71
            <td><var>{{ column.name }}</var></td>
72
          </tr>
73
        {% endfor %}
74
      </tbody>
75
    </table>
76
    <h4 id="help-flags">{% trans "Flags" %}</h4>
77
    <p>{% blocktrans trimmed %}Each column can receive flags after its name, separated by spaces. Each modifier can be prefixed by <var>no-</var> to set its value to false.{% endblocktrans %}</p>
78
    <table class="main left">
79
      <thead>
80
        <tr>
81
          <th>{% trans "Flag" %}</th>
82
          <th>{% trans "Meaning" %}</th>
83
          <th>{% trans "Default value" %}</th>
84
        </tr>
85
      </thead>
86
      <tbody>
87
        <tr>
88
          <td>key</td>
89
          <td>
90
            {% blocktrans trimmed %}
91
            The column is an import key, it is used to match the row with an existing user. Only one column can be an import key.
92
            {% endblocktrans %}
93
          </td>
94
          <td>{% trans "False" %}</td>
95
        </tr>
96
        <tr>
97
          <td>create</td>
98
          <td>
99
            {% blocktrans trimmed %}
100
            Values will be used when creating a new user.
101
            {% endblocktrans %}
102
          </td>
103
          <td>{% trans "True" %}</td>
104
        </tr>
105
        <tr>
106
          <td>update</td>
107
          <td>
108
            {% blocktrans trimmed %}
109
            Values will be used when updating an existing user.
110
            {% endblocktrans %}
111
          </td>
112
          <td>{% trans "True" %}</td>
113
        </tr>
114
        <tr>
115
          <td>unique</td>
116
          <td>
117
            {% blocktrans trimmed %}
118
            Values must be unique in the target organizational unit.
119
            {% endblocktrans %}
120
          </td>
121
          <td>{% trans "False" %} {% blocktrans trimmed %}
122
            (default is True for the <var>email</var> and <var>username</var> columns if they are configured to be unique in the target organizational unit)
123
            {% endblocktrans %}
124
          </td>
125
        </tr>
126
        <tr>
127
          <td>globally-unique</td>
128
          <td>
129
            {% blocktrans trimmed %}
130
            Values must be unique among all users.
131
            {% endblocktrans %}
132
          </td>
133
          <td>{% trans "False" %} {% blocktrans trimmed %}
134
            (default is True for the <var>email</var> and <var>username</var> columns if they are configured to be globally unique)
135
            {% endblocktrans %}</td>
136
        </tr>
137
        <tr>
138
          <td>verified</td>
139
          <td>
140
            {% blocktrans trimmed %}
141
            Values are verified.
142
            {% endblocktrans %}
143
          </td>
144
          <td>{% trans "False" %} {% blocktrans %}(default is True for the <var>email</var> column){% endblocktrans %}</td>
145
        </tr>
146
      </tbody>
147
    </table>
148

  
149
    <h4 id="help-external-identifier">{% trans "External identifier" %}</h4>
150
    <p>
151
      {% blocktrans trimmed %}
152
        You can also use two special columns <var>_source_name</var> and
153
        <var>_source_id</var>. <var>_source_name</var> must be the name of the
154
        source directory from which the users are exported, it must not
155
        change between imports. <var>_source_id</var> is the unique identifier
156
        from the source directory from which the users are extracted, it must
157
        not change between imports and should never be reused for different
158
        users. <var>_source_id</var> is automatically the key column, and you
159
        cannot use another key column.
160
      {% endblocktrans %}
161
    </p>
162
    <h4>{% trans "Examples" %}</h4>
163
    <p>Importing verified first and last name of users keyed by email</p>
164
    <blockquote>
165
      <pre>email key,first_name verified,last_name verified
166
john.doe@example.com,John,Doe
167
</pre>
168
    </blockquote>
169
    <p>Importing email, family_reference, first and last name of users from application <var>app1</var>, ensuring family_reference is unique.</p>
170
    <blockquote>
171
      <pre>_source_name,_source_id,email,family_reference,first_name,last_name
172
app1,1,john.doe@example.com,1234,John,Doe
173
</pre>
174
    </blockquote>
175
  </div>
47 176
{% endblock %}
src/authentic2/manager/user_views.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
import base64
17 18
import datetime
18 19
import collections
19 20
import operator
......
52 53
from .utils import get_ou_count, has_show_username
53 54
from . import app_settings
54 55

  
56
User = get_user_model()
57

  
55 58

  
56 59
class UsersView(HideOUColumnMixin, BaseTableView):
57 60
    template_name = 'authentic2/manager/users.html'
......
659 662

  
660 663
        ctx = super(UserImportsView, self).get_context_data(**kwargs)
661 664
        ctx['imports'] = sorted(user_import.UserImport.all(), key=operator.attrgetter('created'), reverse=True)
665
        help_columns = []
666
        field_columns = ['username', 'email', 'first_name', 'last_name']
667
        key = 'username'
668
        if not has_show_username():
669
            field_columns.remove('username')
670
            key = 'email'
671
        for field_column in field_columns:
672
            field = User._meta.get_field(field_column)
673
            if Attribute.objects.filter(name=field.name).exists():
674
                continue
675
            help_columns.append({
676
                'label': field.verbose_name,
677
                'name': field.name,
678
                'key': field.name == key,
679
            })
680
        for attribute in Attribute.objects.all():
681
            kind = attribute.get_kind()
682
            if not kind.get('csv_importable', True):
683
                continue
684
            help_columns.append({
685
                'label': attribute.label,
686
                'name': attribute.name,
687
                'key': attribute.name == key,
688
            })
689
        ctx['help_columns'] = help_columns
690
        example_data = u','.join(column['name'] + (' key' if column['key'] else '') for column in help_columns) + '\n'
691
        example_url = 'data:text/csv;base64,%s' % base64.b64encode(example_data.encode('utf-8'))
692
        ctx['form'].fields['import_file'].help_text = format_html(
693
            _('{0}. {1} <a download="{3}" href="{2}">{3}</a>'),
694
            ctx['form'].fields['import_file'].help_text,
695
            _('ex.:'),
696
            example_url,
697
            _('users.csv'))
662 698
        return ctx
663 699

  
664 700
user_imports = UserImportsView.as_view()
665
-