Projet

Général

Profil

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

Benjamin Dauvergne, 02 juillet 2019 21:37

Télécharger (11,2 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      | 180 +++++++++++++++---
 src/authentic2/manager/user_views.py          |  36 ++++
 4 files changed, 203 insertions(+), 22 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
23 23
{% endblock %}
24 24

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

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

  
151
    <h4 id="help-external-identifier">{% trans "External identifier" %}</h4>
152
    <p>
153
      {% blocktrans trimmed %}
154
        You can also use two special columns <var>_source_name</var> and
155
        <var>_source_id</var>. <var>_source_name</var> must be the name of the
156
        source directory from which the users are exported, it must not
157
        change between imports. <var>_source_id</var> is the unique identifier
158
        from the source directory from which the users are extracted, it must
159
        not change between imports and should never be reused for different
160
        users. <var>_source_id</var> is automatically the key column, and you
161
        cannot use another key column.
162
      {% endblocktrans %}
163
    </p>
164
    <h4>{% trans "Examples" %}</h4>
165
    <p>Importing first and last name of users keyed by email</p>
166
    <blockquote>
167
      <pre>"email key",first_name,last_name
168
john.doe@example.com,John,Doe
169
</pre>
170
    </blockquote>
171
    <p>Importing verified first and last name of users keyed by email</p>
172
    <blockquote>
173
      <pre>"email key","first_name verified","last_name verified"
174
john.doe@example.com,John,Doe
175
</pre>
176
    </blockquote>
177
    <p>Importing email, family_reference, first and last name of users from application <var>app1</var>, ensuring family_reference is unique.</p>
178
    <blockquote>
179
      <pre>_source_name,_source_id,email,"family_reference unique",first_name,last_name
180
app1,1,john.doe@example.com,1234,John,Doe
181
</pre>
182
    </blockquote>
183
  </div>
48 184
{% 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
-