• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / yast-users / 5453098972

pending completion
5453098972

Pull #383

github

web-flow
Merge 54d62cefa into f91b954c3
Pull Request #383: User creation page got messed when going back after importing user(s) from existing installation

16 of 16 new or added lines in 1 file covered. (100.0%)

3319 of 5513 relevant lines covered (60.2%)

35.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.21
/src/lib/users/dialogs/inst_user_first.rb
1
# Copyright (c) [2016-2022] SUSE LLC
2
#
3
# All Rights Reserved.
4
#
5
# This program is free software; you can redistribute it and/or modify it
6
# under the terms of version 2 of the GNU General Public License as published
7
# by the Free Software Foundation.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12
# more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with this program; if not, contact SUSE LLC.
16
#
17
# To contact SUSE LLC about this file by physical or electronic mail, you may
18
# find current contact information at www.suse.com.
19

20
require "yast"
1✔
21
require "yast2/execute"
1✔
22
require "ui/installation_dialog"
1✔
23
require "users/dialogs/users_to_import"
1✔
24
require "y2users"
1✔
25
require "y2users/help_texts"
1✔
26
require "y2users/password_helper"
1✔
27
require "y2users/username"
1✔
28
require "y2users/config_manager"
1✔
29
require "users/users_database"
1✔
30
require "tmpdir"
1✔
31
require "pathname"
1✔
32

33
module Yast
1✔
34
  # Dialog for the creation of local users during the installation
35
  #
36
  # rubocop:disable Metrics/ClassLength
37
  class InstUserFirstDialog < ::UI::InstallationDialog
1✔
38
    include Y2Users::PasswordHelper
1✔
39

40
    # Widgets to enable/disable depending on the selected action
41
    # (the first one receives the initial focus if applicable)
42
    WIDGETS = {
43
      new_user: [:full_name, :username, :pw1, :pw2, :root_pw, :autologin],
1✔
44
      import:   [:choose_users, :import_qty_label],
45
      skip:     []
46
    }.freeze
47
    private_constant :WIDGETS
1✔
48

49
    # @return [Symbol] Action selected by the user. Possible values are
50
    #     :new_user, :import (only possible during installation) and :skip.
51
    attr_reader :action
1✔
52

53
    # Constructor
54
    #
55
    # @param config [Y2Users::Config] Config where the changes are reflected (it is modified).
56
    # @param user [Y2Users::User] User to work on. If no user is given, then a new user is created.
57
    def initialize(config, user: nil)
1✔
58
      super()
33✔
59
      import_yast_modules
33✔
60
      textdomain "users"
33✔
61

62
      @config = config
33✔
63
      # The dialog does not support to have both at the same time, imported users and a new user.
64
      @user = user unless imported_users? || !earlier_imported_users.empty?
33✔
65

66
      # NOTE: the only way to know if the user is going to be created or edited is through
67
      # {Y2Users::ConfigElement#attached?} method BEFORE the #user method attaches it to the current
68
      # #config for validation purposes. See #editing_user?
69
      @editing_user = !!user&.attached?
33✔
70

71
      @login_modified = false
33✔
72
      # do not open package progress wizard window
73
      @progress_orig = Progress.set(false)
33✔
74

75
      init_user_attributes
33✔
76
      init_autologin
33✔
77
      init_pw_for_root
33✔
78

79
      @usernames_to_import = if earlier_imported_users
33✔
80
        earlier_imported_users.map(&:name)
33✔
81
      else
82
        imported_users.map(&:name)
×
83
      end
84

85
      init_action
33✔
86
    end
87

88
    def run
1✔
89
      # Fate #326447: Allow system role to default to no local user
90
      return :auto unless enable_local_users?
1✔
91

92
      super
×
93
    end
94

95
    # UI sends events as user types the full name
96
    def full_name_handler
1✔
97
      # reenable suggestion
98
      @login_modified = false if UI.QueryWidget(Id(:username), :Value).empty?
×
99
      propose_login unless @login_modified
×
100
    end
101

102
    def username_handler
1✔
103
      @login_modified = true
×
104
    end
105

106
    def choose_users_handler
1✔
107
      imported = UsersToImportDialog.new(importable_users.map(&:name), @usernames_to_import).run
8✔
108
      return unless imported
8✔
109

110
      @usernames_to_import = imported
6✔
111
      UI.ReplaceWidget(Id(:import_qty), import_qty_widget)
6✔
112
    end
113

114
    def next_handler
1✔
115
      success = case action
22✔
116
      when :new_user
117
        new_user_action
13✔
118
      when :import
119
        import_action
6✔
120
      when :skip
121
        skip_action
3✔
122
      end
123

124
      super if success
22✔
125
    end
126

127
    def skip_handler
1✔
128
      self.action = :skip
×
129
    end
130

131
    def new_user_handler
1✔
132
      self.action = :new_user
×
133
    end
134

135
    def import_handler
1✔
136
      self.action = :import
×
137
    end
138

139
    def help_text
1✔
140
      InstUserFirstHelp.new(import_available?).text
×
141
    end
142

143
  private
1✔
144

145
    attr_reader :config
1✔
146

147
    # Imports all the used YaST modules
148
    #
149
    # Importing them before class initialization has been observed to
150
    # be problematic
151
    def import_yast_modules
1✔
152
      Yast.import "UI"
33✔
153
      Yast.import "GetInstArgs"
33✔
154
      Yast.import "Label"
33✔
155
      Yast.import "Mode"
33✔
156
      Yast.import "Popup"
33✔
157
      Yast.import "Progress"
33✔
158
      Yast.import "Report"
33✔
159
      Yast.import "ProductFeatures"
33✔
160
      Yast.import "Autologin"
33✔
161
    end
162

163
    # Check if creating local users is enabled (default) or disabled in the
164
    # control.xml file during the installation.
165
    #
166
    # @return Boolean
167
    def enable_local_users?
1✔
168
      ProductFeatures::GetBooleanFeatureWithFallback("globals", "enable_local_users", true)
1✔
169
    end
170

171
    def init_focus
1✔
172
      widget = WIDGETS[action].first
×
173
      UI.SetFocus(Id(widget)) if widget
×
174
    end
175

176
    # Sets the initial value for the action selection
177
    def init_action
1✔
178
      # when going back in installation imported_users is not initialized yet.
179
      @action = if imported_users? || !@usernames_to_import.empty?
33✔
180
        :import
×
181
      elsif editing_user?
33✔
182
        :new_user
4✔
183
      else
184
        # New user is the default option
185
        GetInstArgs.going_back ? :skip : :new_user
29✔
186
      end
187
    end
188

189
    # Initializes the instance variables used to configure a new user
190
    def init_user_attributes
1✔
191
      @username = user.name || ""
33✔
192
      @full_name = user.full_name || ""
33✔
193
      @password = user.password_content || ""
33✔
194
    end
195

196
    # Sets the initial default value for autologin
197
    def init_autologin
1✔
198
      @autologin = config.login? ? config.login.autologin? : false
33✔
199
      # The autologin value from the control file is used only when opening the dialog for first
200
      # time, see {#editing_user?}.
201
      return if editing_user? || @autologin
33✔
202

203
      @autologin = true if ProductFeatures.GetBooleanFeature("globals", "enable_autologin") == true
29✔
204
      Builtins.y2debug("autologin default value: %1", @autologin)
29✔
205
    end
206

207
    # Sets the initial default value for root pw checkbox
208
    def init_pw_for_root
1✔
209
      @use_pw_for_root = root_password_matches?
33✔
210
      # Initial status of the "user password for root" option, see {#update_root_password}.
211
      @initial_use_pw_for_root = @use_pw_for_root
33✔
212

213
      # The the control file setting is used only when opening the dialog for first time, see
214
      # {#editing_user?}.
215
      return if editing_user? || @use_pw_for_root
33✔
216

217
      if ProductFeatures.GetBooleanFeature("globals", "root_password_as_first_user") == true
29✔
218
        @use_pw_for_root = true
29✔
219
      end
220

221
      Builtins.y2debug("root_pw default value: %1", @use_pw_for_root)
29✔
222
    end
223

224
    # User to work on
225
    #
226
    # @return [Y2Users::User]
227
    def user
1✔
228
      @user ||= Y2Users::User.new("")
187✔
229

230
      config.attach(@user) unless @user.attached?
187✔
231

232
      @user
187✔
233
    end
234

235
    # Root user for which is possible to define the password during the :new_user action
236
    #
237
    # @return [Y2Users::User]
238
    def root_user
1✔
239
      @root_user ||= config.users.root || Y2Users::User.create_root
51✔
240

241
      config.attach(@root_user) unless @root_user.attached?
51✔
242

243
      @root_user
51✔
244
    end
245

246
    # Whether the user is being edited
247
    #
248
    # It is considered that the user is going to be edited if it was not attached to a configuration
249
    # when the dialog was initialized
250
    #
251
    # @return [Boolean]
252
    def editing_user?
1✔
253
      @editing_user
99✔
254
    end
255

256
    # Checks whether the current information of the user is valid, reporting the problem otherwise
257
    #
258
    # @return [Boolean]
259
    def valid_user?
1✔
260
      issue = user.issues(skip: [:password]).first
12✔
261

262
      return true unless issue
12✔
263

264
      Yast::Report.Error(issue.message)
1✔
265
      focus_on(issue.location)
1✔
266

267
      false
1✔
268
    end
269

270
    # Whether chosen password if valid or not
271
    #
272
    # Note that validations are performed over a copy of
273
    #
274
    #   * {#root_user} when using the same password for root
275
    #   * {#user} when not
276
    #
277
    # @param password [Y2Users::Password] the password to be validated
278
    # @return [Boolean] true when given a valid password; false otherwise
279
    def valid_password?(password)
1✔
280
      target_user = @use_pw_for_root ? root_user : user
10✔
281
      user_to_validate = target_user.copy
10✔
282
      user_to_validate.password = password
10✔
283

284
      valid_password_for?(user_to_validate)
10✔
285
    end
286

287
    # Sets the UI focus in the widget corresponding to the given issue location
288
    #
289
    # @param location [Y2Issues::Location]
290
    def focus_on(location)
1✔
291
      id = (location.path == "name") ? :username : :full_name
1✔
292
      Yast::UI.SetFocus(Id(id))
1✔
293
    end
294

295
    def dialog_title
1✔
296
      import_available? ? _("Local Users") : _("Local User")
×
297
    end
298

299
    def title_icon
1✔
300
      "yast-users"
×
301
    end
302

303
    def create_dialog
1✔
304
      super
×
305
      refresh
×
306
      init_focus
×
307
      true
×
308
    end
309

310
    def close_dialog
1✔
311
      super
×
312
      Progress.set(@progress_orig)
×
313
    end
314

315
    # When going back it tries to guess whether stored users were previously imported
316
    #
317
    # It checks wheter the users are in between importable users (@see importable_users).
318
    # If an already configured user can be found between importable ones, then it is assumed
319
    # to be a previously imported one.
320
    #
321
    # return [Array<User>] list of earlier imported users
322
    def earlier_imported_users
1✔
323
      return [] if !GetInstArgs.going_back
99✔
324

325
      # these keys breaks the comparison
326
      # - gid is usually having some value for importable but no value (nil) for configured user.
327
      # This might be potential bug
328
      # - password is also doing mess. Most probably because it is loaded hashed
329
      rejected_keys = [:gid, :password]
×
330

331
      config = Y2Users::ConfigManager.instance.target
×
332

333
      @earlier_imported_users ||= config.users.select do |u|
×
334
        importable_users.any? do |iu|
×
335
          u_hash = u.eql_hash.reject { |k, _| rejected_keys.include?(k) }
×
336
          iu_hash = iu.eql_hash.reject { |k, _| rejected_keys.include?(k) }
×
337

338
          u_hash == iu_hash
×
339
        end
340
      end
341
    end
342

343
    # Whether there are imported user
344
    #
345
    # @return [Boolean]
346
    def imported_users?
1✔
347
      imported_users.any?
83✔
348
    end
349

350
    # Imported users from the current config
351
    #
352
    # Note that imported users contain all the relevant information while non-imported users that
353
    # are created during the install process doesn't even have an uid yet at this point.
354
    #
355
    # @return [Array<Y2Users::User>]
356
    def imported_users
1✔
357
      @imported_users = config.users.select { |u| importable_users.any?(u) }
249✔
358
    end
359

360
    # Users database that was imported from a different system (done during pre_install)
361
    #
362
    # @return [::Users::UserDatabase, nil] nil if there are no users to be imported
363
    def importing_database
1✔
364
      ::Users::UsersDatabase.all.first
170✔
365
    end
366

367
    # Users from a different system that can be imported into the new installation
368
    #
369
    # @return [Array<Y2Users::User>]
370
    def importable_users
1✔
371
      importing_database&.users || []
164✔
372
    end
373

374
    # Returns a copy of the given user with sanitized data
375
    #
376
    # It removes the information about the group if the group is not included in the current config.
377
    #
378
    # @param user [Y2Users::User]
379
    # @return [Y2Users::User]
380
    def sanitized_user(user)
1✔
381
      user.copy.tap do |u|
12✔
382
        group = config.groups.by_gid(u.gid).first
12✔
383
        u.gid = nil unless group
12✔
384
      end
385
    end
386

387
    # Whether the password of root and the new user are equal
388
    #
389
    # @return [Boolean]
390
    def root_password_matches?
1✔
391
      value = root_user&.password&.value
44✔
392
      return false unless value&.plain?
44✔
393

394
      value.content == @password
×
395
    end
396

397
    # Proposes the username based on the entered full name
398
    #
399
    # @see Y2Users::Username.generate_from
400
    def propose_login
1✔
401
      full_name = UI.QueryWidget(Id(:full_name), :Value)
×
402
      login = Y2Users::Username.generate_from(full_name)
×
403

404
      UI.ChangeWidget(Id(:username), :Value, login)
×
405
    end
406

407
    def refresh
1✔
408
      WIDGETS.values.flatten.each do |w|
×
409
        enable = WIDGETS[action].include?(w)
×
410
        enable = false if w == :autologin && enable && !Autologin.supported?
×
411
        UI.ChangeWidget(Id(w), :Enabled, enable)
×
412
      end
413
    end
414

415
    def action=(value)
1✔
416
      @action = value
×
417
      refresh
×
418
    end
419

420
    # Action for the new user option
421
    #
422
    # Processes the form and performs the actions needed
423
    #
424
    # @return [Boolean] whether everything was ok
425
    def new_user_action
1✔
426
      return false unless process_new_user_form
13✔
427

428
      perform_new_user
8✔
429

430
      true
8✔
431
    end
432

433
    # Action for the import option
434
    #
435
    # Processes the form and performs the actions needed
436
    #
437
    # @return [Boolean] whether everything was ok
438
    def import_action
1✔
439
      return false unless process_import_form
6✔
440

441
      perform_import
6✔
442

443
      true
6✔
444
    end
445

446
    # Action for the skip option
447
    #
448
    # Processes the form and performs the actions needed
449
    #
450
    # @return [Boolean] whether everything was ok
451
    def skip_action
1✔
452
      return false unless process_skip_form
3✔
453

454
      perform_skip
3✔
455

456
      true
3✔
457
    end
458

459
    def process_new_user_form
1✔
460
      @use_pw_for_root = UI.QueryWidget(Id(:root_pw), :Value)
13✔
461

462
      # username checks
463
      @username = UI.QueryWidget(Id(:username), :Value)
13✔
464
      if @username.empty?
13✔
465
        Report.Error(
1✔
466
          # TRANSLATORS: Error popup
467
          _("The new username cannot be blank.\n" \
468
            "If you don't want to create a user now, select\n" \
469
            "'Skip User Creation'.")
470
        )
471
        return false
1✔
472
      end
473

474
      @full_name = UI.QueryWidget(Id(:full_name), :Value)
12✔
475

476
      user.name = @username
12✔
477
      user.gecos = [@full_name].compact
12✔
478
      # In case of editing an existing user, the home should be updated in order to keep the home
479
      # path as /home/new_username.
480
      update_home
12✔
481

482
      return false unless valid_user?
12✔
483

484
      return false unless process_password
11✔
485

486
      @autologin = UI.QueryWidget(Id(:autologin), :Value)
8✔
487

488
      true
8✔
489
    end
490

491
    # Updates the user home path if needed
492
    def update_home
1✔
493
      return if !user.home&.path || user.home.path.empty?
12✔
494

495
      home_path = Pathname.new(user.home.path)
1✔
496

497
      return if user.name == home_path.basename.to_s
1✔
498

499
      user.home.path = home_path.dirname.join(user.name).to_s
1✔
500
    end
501

502
    # Processes the password for the user
503
    #
504
    # Errors could be reported.
505
    #
506
    # @return [Boolean] if the password was correctly assigned to the user
507
    def process_password
1✔
508
      # password checks
509
      pw1 = UI.QueryWidget(Id(:pw1), :Value)
11✔
510
      pw2 = UI.QueryWidget(Id(:pw2), :Value)
11✔
511

512
      if pw1 != pw2
11✔
513
        # TRANSLATORS: error popup
514
        Report.Error(_("The passwords do not match.\nTry again."))
1✔
515
        return false
1✔
516
      end
517

518
      password = Y2Users::Password.create_plain(pw1)
10✔
519

520
      return false unless valid_password?(password)
10✔
521

522
      user.password = password
8✔
523
      true
8✔
524
    end
525

526
    def perform_new_user
1✔
527
      remove_imported_users
8✔
528
      update_root_password
8✔
529
      configure_login
8✔
530
    end
531

532
    def process_import_form
1✔
533
      if @usernames_to_import.empty?
6✔
534
        Report.Error(
×
535
          # TRANSLATORS: error popup
536
          _("No users from the previous installation were choosen.\n" \
537
            "If you don't want to create a user now, select\n" \
538
            "'Skip User Creation'.")
539
        )
540
        return false
×
541
      end
542

543
      @autologin = false
6✔
544
      @use_pw_for_root = false
6✔
545

546
      true
6✔
547
    end
548

549
    def perform_import
1✔
550
      remove_user
6✔
551
      remove_imported_users
6✔
552
      configure_login
6✔
553
      update_root_password
6✔
554

555
      imported_users = importing_database.filtered_config(@usernames_to_import).users.all
6✔
556
      imported_users = imported_users.map { |u| sanitized_user(u) }
18✔
557

558
      config.attach(imported_users)
6✔
559
    end
560

561
    def process_skip_form
1✔
562
      @autologin = false
3✔
563
      @use_pw_for_root = false
3✔
564

565
      true
3✔
566
    end
567

568
    def perform_skip
1✔
569
      remove_user
3✔
570
      remove_imported_users
3✔
571
      configure_login
3✔
572
      update_root_password
3✔
573
    end
574

575
    def remove_user
1✔
576
      config.detach(user)
9✔
577
    end
578

579
    def remove_imported_users
1✔
580
      config.detach(imported_users) if imported_users?
17✔
581
    end
582

583
    # Configures the login options
584
    def configure_login
1✔
585
      autologin_user = @autologin ? user : nil
17✔
586
      config.login ||= Y2Users::LoginConfig.new
17✔
587
      config.login.autologin_user = autologin_user
17✔
588
    end
589

590
    # Updates the root password according to the selected form options
591
    #
592
    # The user password is copied to root when the option "use password for root" is selected in
593
    # the form. Otherwise, there are two cases where the root password should be invalidated:
594
    #
595
    # * When the option "use password for root" was deselected, see {#use_pw_for_root_modified?}.
596
    # * When the new user password matches with the current root password.
597
    def update_root_password
1✔
598
      if @use_pw_for_root
17✔
599
        root_user.password = user.password.copy
1✔
600
      elsif use_pw_for_root_modified? || root_password_matches?
16✔
601
        root_user.password = nil
5✔
602
      end
603
    end
604

605
    # Whether the status of the "use password for root" option in the new user form was modified
606
    #
607
    # @return [Boolean]
608
    def use_pw_for_root_modified?
1✔
609
      @initial_use_pw_for_root != @use_pw_for_root
16✔
610
    end
611

612
    def dialog_content
1✔
613
      HSquash(
×
614
        VBox(
615
          RadioButtonGroup(
616
            Id(:action),
617
            VBox(
618
              new_user_option,
619
              import_option,
620
              skip_option
621
            )
622
          )
623
        )
624
      )
625
    end
626

627
    def new_user_option
1✔
628
      VBox(
×
629
        Left(
630
          RadioButton(
631
            Id(:new_user),
632
            Opt(:notify),
633
            # TRANSLATORS: radio button
634
            _("&Create New User"),
635
            action == :new_user
636
          )
637
        ),
638
        VSpacing(0.3),
639
        Left(
640
          HBox(
641
            HSpacing(5),
642
            new_user_widget
643
          )
644
        ),
645
        VSpacing(1)
646
      )
647
    end
648

649
    def import_option
1✔
650
      if import_available?
×
651
        VBox(
×
652
          Left(
653
            RadioButton(
654
              Id(:import),
655
              Opt(:notify),
656
              # TRANSLATORS: radio button
657
              _("&Import User Data from a Previous Installation"),
658
              action == :import
659
            )
660
          ),
661
          VSpacing(0.3),
662
          Left(
663
            HBox(
664
              HSpacing(5),
665
              ReplacePoint(Id(:import_qty), import_qty_widget),
666
              HSpacing(1),
667
              PushButton(Id(:choose_users), _("Choose Users"))
668
            )
669
          ),
670
          VSpacing(1)
671
        )
672
      else
673
        Empty()
×
674
      end
675
    end
676

677
    def skip_option
1✔
678
      Left(
×
679
        RadioButton(
680
          Id(:skip),
681
          Opt(:notify),
682
          # TRANSLATORS: radio button
683
          _("&Skip User Creation"),
684
          action == :skip
685
        )
686
      )
687
    end
688

689
    def new_user_widget
1✔
690
      VBox(
×
691
        *new_user_fields,
692
        VSpacing(0.2),
693
        *new_user_options
694
      )
695
    end
696

697
    def new_user_fields
1✔
698
      [
699
        InputField(
×
700
          Id(:full_name),
701
          Opt(:notify, :hstretch),
702
          # text entry
703
          _("User's &Full Name"),
704
          @full_name
705
        ),
706
        InputField(
707
          Id(:username),
708
          Opt(:notify, :hstretch),
709
          # input field for login name
710
          _("&Username"),
711
          @username
712
        ),
713
        Password(
714
          Id(:pw1),
715
          Opt(:hstretch),
716
          Label.Password,
717
          @password.nil? ? "" : @password
×
718
        ),
719
        Password(
720
          Id(:pw2),
721
          Opt(:hstretch),
722
          Label.ConfirmPassword,
723
          @password.nil? ? "" : @password
×
724
        )
725
      ]
726
    end
727

728
    def new_user_options
1✔
729
      [
730
        Left(
×
731
          CheckBox(
732
            Id(:root_pw),
733
            # checkbox label
734
            _("U&se this password for system administrator"),
735
            @use_pw_for_root
736
          )
737
        ),
738
        Left(autologin_checkbox)
739
      ]
740
    end
741

742
    def autologin_checkbox
1✔
743
      # checkbox label
744
      label = _("&Automatic Login")
×
745

746
      if Autologin.supported?
×
747
        CheckBox(Id(:autologin), label, @autologin)
×
748
      else
749
        @autologin = false
×
750
        CheckBox(Id(:autologin), Opt(:disabled), label, false)
×
751
      end
752
    end
753

754
    def import_qty_widget
1✔
755
      qty = @usernames_to_import.size
6✔
756
      msg = if qty == 0
6✔
757
        _("No users selected")
×
758
      else
759
        n_("%d user will be imported", "%d users will be imported", qty)
6✔
760
      end
761
      Label(Id(:import_qty_label), msg % qty)
6✔
762
    end
763

764
    def import_available?
1✔
765
      !!importing_database
×
766
    end
767
  end
768
  # rubocop:enable Metrics/ClassLength
769

770
  # Helper class to generate the help text for {InstUserFirstDialog}
771
  class InstUserFirstHelp
1✔
772
    include Y2Users::HelpTexts
1✔
773

774
    # Constructor
775
    #
776
    # @param import [Boolean] value for {#import?}
777
    def initialize(import)
1✔
778
      textdomain "users"
×
779

780
      @import = import
×
781
    end
782

783
    # Full text to display in the help of the form
784
    #
785
    # @return [String] formatted and localized text
786
    def text
1✔
787
      intro + new_user + import_users + skip
×
788
    end
789

790
  private
1✔
791

792
    # Whether the form offers the possibility of importing users from a previous installation
793
    #
794
    # @return [Boolean]
795
    def import?
1✔
796
      !!@import
×
797
    end
798

799
    # @return [String] formatted and localized text
800
    def intro
1✔
801
      _(
×
802
        "<p>\nUse one of the available options to add local users to the system.\n" \
803
        "Local users are stored in <i>/etc/passwd</i> and <i>/etc/shadow</i>.\n</p>\n"
804
      )
805
    end
806

807
    # @return [String] formatted and localized text
808
    def new_user
1✔
809
      "<p>\n<b>" + _("Create new user") + "</b>\n</p>\n" +
×
810
        _(
811
          "<p>\nEnter the <b>User's Full Name</b>, <b>Username</b>, and <b>Password</b> to\n" \
812
          "assign to this user account.\n</p>\n"
813
        ) +
814
        _(
815
          "<p>\nWhen entering a password, distinguish between uppercase and\n" \
816
          "lowercase. Passwords should not contain any accented characters or umlauts.\n</p>\n"
817
        ) +
818
        password_format +
819
        _(
820
          "<p>\nTo ensure that the password was entered correctly,\n" \
821
          "repeat it exactly in a second field. Do not forget your password.\n" \
822
          "</p>\n"
823
        ) +
824
        username_format +
825
        _(
826
          "<p>Check <b>Use this password for system administrator</b> if the " \
827
          "same password as entered for the first user should be used for root.</p>"
828
        ) +
829
        _(
830
          "<p>\nThe username and password created here are needed to log in " \
831
          "and work with your Linux system. With <b>Automatic Login</b> enabled, " \
832
          "the login procedure is skipped. This user is logged in automatically.</p>\n"
833
        )
834
    end
835

836
    # @return [String] formatted and localized text
837
    def import_users
1✔
838
      return "" unless import?
×
839

840
      "<p>\n<b>" + _("Import User Data from a Previous Installation") + "</b>\n</p>\n" +
×
841
        _(
842
          "<p>\nA previous Linux installation with local users has been detected.\n" \
843
          "The information there can be used to create users in the system being installed.\n" \
844
          "Use the <b>Choose Users</b> button to select some users. Their basic information will" \
845
          "\nbe imported.\n</p>\n"
846
        )
847
    end
848

849
    # @return [String] formatted and localized text
850
    def skip
1✔
851
      "<p>\n<b>" + _("Skip User Creation") + "</b>\n</p>\n" +
×
852
        _(
853
          "<p>\nSometimes root is the only needed local user, like in network environments\n" \
854
          "with an authentication server. Select this option to proceed without creating\n" \
855
          "a local user.\n</p>\n"
856
        )
857
    end
858

859
    # Explanation of the format the password must follow in order to be valid
860
    #
861
    # @return [String] formatted and localized text
862
    def password_format
1✔
863
      # TRANSLATORS: %{min} and %{max} will be replaced by numbers
864
      format(
×
865
        _("<p>\nThe password length should be between %{min}\n and %{max} characters.\n</p>\n"),
866
        min: validation_config.min_password_length,
867
        max: validation_config.max_password_length
868
      ) + valid_password_text + ca_password_text
869
    end
870

871
    # Explanation of the format the user name must follow in order to be valid
872
    #
873
    # @return [String] formatted and localized text
874
    def username_format
1✔
875
      _(
×
876
        "<p>\nFor the <b>Username</b> use only letters (no accented characters), digits, and "\
877
        "<tt>._-</tt>.\n" \
878
        "Do not use uppercase letters in this entry unless you know what you are doing.\n" \
879
        "Usernames have stricter restrictions than passwords. You can redefine the\n" \
880
        "restrictions in the /etc/login.defs file. Read its man page for information.\n" \
881
        "</p>\n"
882
      )
883
    end
884
  end
885
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc