diff --git a/cgi/user2.pl b/cgi/user2.pl
new file mode 100644
index 0000000000000..bc6f0d13993ac
--- /dev/null
+++ b/cgi/user2.pl
@@ -0,0 +1,385 @@
+#!/usr/bin/perl -w
+
+# This file is part of Product Opener.
+#
+# Product Opener
+# Copyright (C) 2011-2020 Association Open Food Facts
+# Contact: contact@openfoodfacts.org
+# Address: 21 rue des Iles, 94100 Saint-Maur des Fossés, France
+#
+# Product Opener is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+use Modern::Perl '2017';
+use utf8;
+
+use ProductOpener::Config qw/:all/;
+use ProductOpener::Store qw/:all/;
+use ProductOpener::Index qw/:all/;
+use ProductOpener::Display qw/:all/;
+use ProductOpener::Users qw/:all/;
+use ProductOpener::Lang qw/:all/;
+use ProductOpener::Orgs qw/:all/;
+
+use CGI qw/:cgi :form escapeHTML charset/;
+use URI::Escape::XS;
+use Storable qw/dclone/;
+use Log::Any qw($log);
+
+my @user_groups = qw(producer database app bot moderator pro_moderator);
+
+my $type = param('type') || 'add';
+my $action = param('action') || 'display';
+
+# Passing values to the template
+my $template_data_ref = {};
+
+# If the "Create user" form was submitted from the product edit page
+# save the password parameter and unset it so that the ProductOpener::Display::init()
+# function does not try to authenticate the user (which does not exist yet) with that password
+
+my $new_user_password;
+if (($type eq "add") and (defined param('prdct_mult'))) {
+
+ $new_user_password = param('password');
+ param("password", "");
+}
+
+ProductOpener::Display::init();
+
+
+# $userid will contain the user to be edited, possibly different than $User_id
+# if an administrator edits another user
+
+my $userid = $User_id;
+
+if (defined param('userid')) {
+
+ $userid = param('userid');
+
+ # The userid looks like an e-mail
+ if ($admin and ($userid =~ /\@/)) {
+ my $emails_ref = retrieve("$data_root/users_emails.sto");
+ if (defined $emails_ref->{$userid}) {
+ $userid = $emails_ref->{$userid}[0];
+ }
+ }
+
+ $userid = get_fileid($userid, 1);
+}
+
+$log->debug("user form - start", { type => $type, action => $action, userid => $userid, User_id => $User_id }) if $log->is_debug();
+
+my $html = '';
+my $js = '';
+
+my $user_ref = {};
+
+if ($type =~ /^edit/) {
+ $user_ref = retrieve("$data_root/users/$userid.sto");
+ if (not defined $user_ref) {
+ display_error($Lang{error_invalid_user}{$lang}, 404);
+ }
+}
+else {
+ $type = 'add';
+}
+
+if (($type =~ /^edit/) and ($User_id ne $userid) and not $admin) {
+ display_error($Lang{error_no_permission}{$lang}, 403);
+}
+
+my $debug = 0;
+my @errors = ();
+
+if ($action eq 'process') {
+
+ if ($type eq 'edit') {
+ if (param('delete') eq 'on') {
+ if ($admin) {
+ $type = 'delete';
+ }
+ else {
+ display_error($Lang{error_no_permission}{$lang}, 403);
+ }
+ }
+ }
+
+ if ($type eq 'edit_owner') {
+ ProductOpener::Users::check_edit_owner($user_ref, \@errors);
+ }
+ elsif ($type ne 'delete') {
+ ProductOpener::Users::check_user_form($type, $user_ref, \@errors);
+ }
+
+ if ($#errors >= 0) {
+ if ($type eq 'edit_owner') {
+ $action = 'none';
+ }
+ else {
+ $action = 'display';
+ }
+ }
+}
+
+$template_data_ref->{action} = $action;
+$template_data_ref->{errors} = \@errors;
+
+$log->debug("user form - before display / process", { type => $type, action => $action, userid => $userid }) if $log->is_debug();
+
+if ($action eq 'display') {
+
+ # We can pre-fill the form to create an account using the username and password
+ # passed in a form to open a session.
+ # e.g. when a non-logged user clicks on the "Edit product" button
+
+ if (($type eq "add") and (defined param("user_id"))) {
+ my $user_info = remove_tags_and_quote(param('user_id'));
+ $user_info =~ /^(.+?)@/;
+ if ( defined ($1) ){
+ $user_ref->{email} = $user_info;
+ $user_ref->{userid} = $1;
+ $user_ref->{name} = $1;
+ $user_ref->{password} = $new_user_password;
+ }
+ else{
+ $user_ref->{userid} = $user_info;
+ $user_ref->{name} = $user_info;
+ $user_ref->{password} = $new_user_password;
+ }
+ }
+
+ $template_data_ref->{user_ref} = $user_ref;
+
+ # Create the list of sections and fields
+
+ $template_data_ref->{sections} = [];
+
+ if ($user_ref) {
+ push @{$template_data_ref->{sections}}, {
+ id => "user",
+ fields => [
+ {
+ field => "name"
+ },
+ {
+ field => "email",
+ type => "email",
+ },
+ {
+ field => "userid",
+ label => "username"
+ },
+ {
+ field => "password",
+ type => "password",
+ label => "password"
+ },
+ {
+ field => "confirm_password",
+ type => "password",
+ label => "password_confirm"
+ },
+ ]
+ };
+
+ # Professional account
+ push @{$template_data_ref->{sections}}, {
+ id => "professional",
+ name => lang("pro_account"),
+ description => "if_you_work_for_a_producer",
+ note => "producers_platform_description_long",
+ fields => [
+ {
+ field => "pro",
+ type => "checkbox",
+ label => lang("this_is_a_pro_account"),
+ warning => sprintf(lang("this_is_a_pro_account_for_org"),"" . $user_ref->{org} . ""),
+ value => "off",
+ },
+ {
+ field => "pro_checkbox",
+ type => "hidden",
+ value => 1,
+ },
+ {
+ field => "requested_org",
+ label => lang("producer_or_brand") . ":",
+ }
+ ]
+ };
+
+ # Teams section
+ my $team_section_ref = {
+ id => "teams",
+ name => lang("teams") . " (" . lang("optional") . ")",
+ description => "teams_description",
+ note => "teams_names_warning",
+ fields => []
+ };
+ for (my $i = 1; $i <= 3; $i++) {
+ push @{$team_section_ref->{fields}}, {
+ field => "team_". $i,
+ label => sprintf(lang("team_s"), $i),
+ };
+ };
+
+ push @{$template_data_ref->{sections}}, {%$team_section_ref};
+
+ # Admin section
+ my $administrator_section_ref = {
+ id => "administrator",
+ name => "Administrator fields",
+ fields => []
+ };
+ push @{$administrator_section_ref->{fields}}, {
+ field => "org",
+ label => lang("organization"),
+ };
+ foreach my $group (@user_groups) {
+ push @{$administrator_section_ref->{fields}}, {
+ field => "user_group_". $group,
+ label => lang("user_group_". $group) . " " . lang("user_group_" . ${group} . "_description"),
+ type => "checkbox",
+ value => $user_ref->{$group},
+ };
+ };
+
+ push @{$template_data_ref->{sections}}, {%$administrator_section_ref};
+ }
+
+ if ( ( defined $user_ref->{org} ) and ( $user_ref->{org} ne "" ) ) {
+
+ $template_data_ref->{accepted_organization} = $user_ref->{org};
+ $template_data_ref->{pro_account_org} = sprintf(lang("this_is_a_pro_account_for_org"),"" . $user_ref->{org} . "");
+ }
+ elsif ((defined $options{product_type}) and ($options{product_type} eq "food")) {
+ my $requested_org_ref = retrieve_org($user_ref->{requested_org});
+ $template_data_ref->{requested_org_ref} = $requested_org_ref;
+ $template_data_ref-> {org_name} = sprintf(lang("add_user_existing_org"), org_name($requested_org_ref));
+ $template_data_ref->{teams_flag} = not ((defined $server_options{private_products}) and ($server_options{private_products}));
+ }
+
+ # Add labels, types, descriptions, notes and existing values for all fields
+ foreach my $section_ref (@{$template_data_ref->{sections}}) {
+
+ # Descriptions and notes for sections
+ if (defined $section_ref->{id}) {
+ if ($section_ref->{description}) {
+ $section_ref->{description} = lang($section_ref->{description});
+ }
+ if ($section_ref->{note}) {
+ $section_ref->{note} = lang($section_ref->{note});
+ }
+ }
+
+ foreach my $field_ref (@{$section_ref->{fields}}) {
+
+ my $field = $field_ref->{field};
+
+ # Default to text field
+ if (not defined $field_ref->{type}) {
+ $field_ref->{type} = "text";
+ };
+
+ # id to use for lang() strings
+ my $field_lang_id = $field;
+
+ if (not defined $field_ref->{value}) {
+ $field_ref->{value} = $user_ref->{$field};
+ };
+
+ # Label
+ if (not defined $field_ref->{label}) {
+ $field_ref->{label} = lang($field_lang_id);
+ };
+
+ if (((defined $user_ref->{pro}) and ($user_ref->{pro}))
+ or ((defined $server_options{producers_platform}) and ($type eq "add"))) {
+ if (($section_ref->{id} eq "professional") and $field_ref->{type} eq "checkbox") {
+ $field_ref->{value} = "on";
+ }
+ };
+ };
+ };
+
+}
+
+elsif ($action eq 'process') {
+
+ if (($type eq 'add') or ($type =~ /^edit/)) {
+ ProductOpener::Users::process_user_form($type, $user_ref);
+ }
+ elsif ($type eq 'delete') {
+ ProductOpener::Users::delete_user($user_ref);
+ }
+
+ if ($type eq 'add') {
+
+ $template_data_ref->{user_requested_org} = $user_ref->{requested_org};
+
+ my $requested_org_ref = retrieve_org($user_ref->{requested_org});
+ $template_data_ref->{add_user_existing_org} = sprintf(lang("add_user_existing_org"), org_name($requested_org_ref));
+
+ $template_data_ref->{user_org} = $user_ref->{org};
+
+ $template_data_ref->{server_options_producers_platform} = $server_options{producers_platform};
+
+ my $pro_url = "https://" . $subdomain . ".pro." . $server_domain . "/";
+ $template_data_ref->{add_user_pro_url} = sprintf(lang("add_user_you_can_edit_pro_promo"), $pro_url);
+
+ $template_data_ref->{add_user_you_can_edit} = sprintf(lang("add_user_you_can_edit"), lang("get_the_app_link"));
+ $template_data_ref->{add_user_join_the_project} = sprintf(lang("add_user_join_the_project"), lang("site_name"));
+ }
+
+}
+
+$template_data_ref->{debug} = $debug;
+$template_data_ref->{userid} = $userid;
+$template_data_ref->{type} = $type;
+
+my $full_width = 1;
+if ($action ne 'display') {
+ $full_width = 0;
+}
+
+if (($type eq "edit_owner") and ($action eq "process")) {
+ $log->info("redirecting to / after changing owner", { }) if $log->is_info();
+
+ my $r = shift;
+ $r->headers_out->set(Location =>"/");
+ $r->status(302);
+ return 302;
+}
+else {
+
+ my $title = lang($type . '_user_' . $action);
+
+ $log->debug("user form - template data", { template_data_ref => $template_data_ref }) if $log->is_debug();
+
+ process_template('user_form2.tt.html', $template_data_ref, \$html) or $html = "
" . $tt->error() . "
";
+ process_template('user_form2.tt.js', $template_data_ref, \$js);
+
+ $initjs .= $js;
+ $scripts .= <
+
+HTML
+;
+
+ display_new( {
+ title=>$title,
+ content_ref=>\$html,
+ full_width=>$full_width,
+ });
+}
\ No newline at end of file
diff --git a/templates/user_form2.tt.html b/templates/user_form2.tt.html
new file mode 100644
index 0000000000000..75feaf4496b1e
--- /dev/null
+++ b/templates/user_form2.tt.html
@@ -0,0 +1,212 @@
+
+
+
+
+[% IF action == 'display' || action == 'none' %]
+[% INCLUDE 'error_list.tt.html' %]
+[% END %]
+
+[% IF action == 'display' %]
+
+
+
+
+
+
+
+[% ELSIF action == 'process' %]
+ [% lang('${type}_user_result') %]
+
+ [% IF type == 'add' %]
+
+
+
+ [% IF user_requested_org.defined %]
+
+
+
+
+
[% add_user_existing_org %]
+
[% lang("add_user_existing_org_pending") %]
+
[% lang("please_email_producers") %]
+
+
+ [% ELSIF user_org.defined %]
+
+
+
+ [% IF server_options_producers_platform.defined %]
+
+
+
+
+
+ [% lang("add_user_you_can_edit_pro") %]
+ → [% lang("import_product_data") %]
+
+ [% ELSE %]
+
+
+
+ [% add_user_pro_url %]
+
+ [% END %]
+
+ [% ELSE %]
+
+
+
+
+ [% add_user_you_can_edit %]
+ [% add_user_join_the_project %]
+ [% lang("add_user_join_us_on_slack") %]
+ → [% lang("join_us_on_slack") %]
+
+ [% END %]
+
+ [% END %]
+
+ [% IF type == 'add' || type == 'edit' %]
+
+
+
+ [% IF !(server_options_producers_platform) %]
+ [% lang("you_can_also_help_us") %]
+ [% lang("bottom_content") %]
+ [% END %]
+
+ [% END %]
+
+[% END %]
+
+[% IF debug %]
+ type: [% type %] action: [% action %] userid: [% userid %]
+[% END %]
diff --git a/templates/user_form2.tt.js b/templates/user_form2.tt.js
new file mode 100644
index 0000000000000..66fe2f43bf7c4
--- /dev/null
+++ b/templates/user_form2.tt.js
@@ -0,0 +1,15 @@
+\$('#pro').change(function() {
+ if (\$(this).prop('checked')) {
+ \$('.pro_org_display').show();
+ \$('.tr_teams').hide();
+ } else {
+ \$('.pro_org_display').hide();
+ \$('.tr_teams').show();
+ }
+ \$(document).foundation('equalizer', 'reflow');
+});
+
+if (\$('#pro').prop('checked')) {
+ \$('.pro_org_display').show();
+ \$('.tr_teams').hide();
+}
\ No newline at end of file