summaryrefslogtreecommitdiff
path: root/lib/tasks/init.rake
blob: 1657534503c057745bbf55c144ea2dce879ce74f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
namespace :cccms do
  desc "Bootstrap a fresh installation: the node skeleton and one admin " \
       "account. Idempotent -- every step finds before it creates, so " \
       "re-running after a new step is added is safe. " \
       "Requires ADMIN_PASS. ADMIN_LOGIN and ADMIN_EMAIL are optional. " \
       "The admin is created without the role and promoted with " \
       "update_column, because admin_needs_second_factor refuses a NEW " \
       "admin without an enrolled factor -- it exempts retention, not " \
       "creation. The account therefore cannot do user management until " \
       "it enrols a second factor and signs in again; see INSTALL.md."
  task :init => :environment do
    password = ENV["ADMIN_PASS"].to_s
    abort "usage: ADMIN_PASS=secret bundle exec rake cccms:init" if password.empty?
    abort "ADMIN_PASS must be at least 6 characters" if password.length < 6

    login = ENV.fetch("ADMIN_LOGIN", "admin")
    email = ENV.fetch("ADMIN_EMAIL", "admin@example.org")

    # publish_draft! is called with no user, which guard_live_change! treats
    # as a trusted system context -- the documented nil-user path, and the
    # reason a rake task can publish into /updates and /disclosure at all.
    ensure_node = lambda do |parent, slug, title, body|
      existing = parent ? parent.children.find_by(:slug => slug) : Node.root
      if existing
        puts format("  %-14s exists   (%d)", slug || "root", existing.id)
        next existing
      end

      node = parent ? parent.children.create!(:slug => slug) : Node.create!
      if parent.nil?
        node.reload
        node.update_column(:draft_id, node.pages.first.id) if node.draft_id.nil?
      end
      Globalize.with_locale(I18n.default_locale) do
        node.draft.update!(:title => title, :body => body.to_s)
      end
      node.publish_draft! if parent
      puts format("  %-14s created  (%d)", slug || "root", node.id)
      node
    end

    puts "Node skeleton:"
    root = ensure_node.(nil, nil, "CCC", "")

    # Referencing it is enough: Node.trash self-creates on first call.
    puts format("  %-14s ready    (%d)", "trash", Node.trash.id)

    ensure_node.(root, "home", "Startseite", "")

    ensure_node.(root, "updates", "Updates",
      '[aggregate tags="update" limit="30" order_by="published_at" order_direction="DESC"]')

    ensure_node.(root, "disclosure", "Disclosure", "")

    club = ensure_node.(root, "club", "Chaos Computer Club", "")
    ensure_node.(club, "erfas", "Erfa-Kreise",
      '[aggregate children="direct" order_by="slug" partial="chapter"]')
    ensure_node.(club, "chaostreffs", "Chaostreffs",
      '[aggregate children="direct" order_by="slug" partial="chapter"]')

    puts
    if User.any?
      puts "Accounts exist already; skipping admin creation."
    else
      user = User.create!(:login => login, :email => email,
                          :password => password,
                          :password_confirmation => password)
      user.update_column(:roles, %w[admin redaktion])
      puts "Created #{user.login} <#{user.email}> as admin + redaktion."
      puts
      puts "This account has no second factor, so it cannot yet create"
      puts "users, reset factors or deactivate accounts. To finish:"
      puts "  1. sign in as #{user.login}"
      puts "  2. Mein Konto -> enable second factor, scan the QR, confirm"
      puts "  3. sign out and sign in again, entering the code"
      puts "Elevation is granted at that login and user management unlocks."
    end
  end
end