From b4f8fb24f34c16e469598c4f594e0041a94614ff Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Fri, 30 Jul 2021 18:11:48 +0200
Subject: [PATCH] Add instruction model

---
 .../alsijil/migrations/0014_instruction.py    | 38 +++++++++++++++++++
 aleksis/apps/alsijil/models.py                | 37 +++++++++++++++++-
 2 files changed, 73 insertions(+), 2 deletions(-)
 create mode 100644 aleksis/apps/alsijil/migrations/0014_instruction.py

diff --git a/aleksis/apps/alsijil/migrations/0014_instruction.py b/aleksis/apps/alsijil/migrations/0014_instruction.py
new file mode 100644
index 000000000..48525627f
--- /dev/null
+++ b/aleksis/apps/alsijil/migrations/0014_instruction.py
@@ -0,0 +1,38 @@
+# Generated by Django 3.2.5 on 2021-07-30 16:10
+
+import django.core.validators
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0019_fix_uniqueness_per_site'),
+        ('sites', '0002_alter_domain_unique'),
+        ('alsijil', '0013_fix_uniqueness_per_site'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Instruction',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('extended_data', models.JSONField(default=dict, editable=False)),
+                ('name', models.CharField(max_length=255, verbose_name='Name')),
+                ('icon', models.CharField(blank=True, choices=[('3d_rotation', '3d_rotation'), ('ac_unit', 'ac_unit'), ('access_alarm', 'access_alarm'), ('access_alarms', 'access_alarms'), ('access_time', 'access_time'), ('accessibility', 'accessibility'), ('accessible', 'accessible'), ('account_balance', 'account_balance'), ('account_balance_wallet', 'account_balance_wallet'), ('account_box', 'account_box'), ('account_circle', 'account_circle'), ('adb', 'adb'), ('add', 'add'), ('add_a_photo', 'add_a_photo'), ('add_alarm', 'add_alarm'), ('add_alert', 'add_alert'), ('add_box', 'add_box'), ('add_circle', 'add_circle'), ('add_circle_outline', 'add_circle_outline'), ('add_location', 'add_location'), ('add_shopping_cart', 'add_shopping_cart'), ('add_to_photos', 'add_to_photos'), ('add_to_queue', 'add_to_queue'), ('adjust', 'adjust'), ('airline_seat_flat', 'airline_seat_flat'), ('airline_seat_flat_angled', 'airline_seat_flat_angled'), ('airline_seat_individual_suite', 'airline_seat_individual_suite'), ('airline_seat_legroom_extra', 'airline_seat_legroom_extra'), ('airline_seat_legroom_normal', 'airline_seat_legroom_normal'), ('airline_seat_legroom_reduced', 'airline_seat_legroom_reduced'), ('airline_seat_recline_extra', 'airline_seat_recline_extra'), ('airline_seat_recline_normal', 'airline_seat_recline_normal'), ('airplanemode_active', 'airplanemode_active'), ('airplanemode_inactive', 'airplanemode_inactive'), ('airplay', 'airplay'), ('airport_shuttle', 'airport_shuttle'), ('alarm', 'alarm'), ('alarm_add', 'alarm_add'), ('alarm_off', 'alarm_off'), ('alarm_on', 'alarm_on'), ('album', 'album'), ('all_inclusive', 'all_inclusive'), ('all_out', 'all_out'), ('android', 'android'), ('announcement', 'announcement'), ('apps', 'apps'), ('archive', 'archive'), ('arrow_back', 'arrow_back'), ('arrow_downward', 'arrow_downward'), ('arrow_drop_down', 'arrow_drop_down'), ('arrow_drop_down_circle', 'arrow_drop_down_circle'), ('arrow_drop_up', 'arrow_drop_up'), ('arrow_forward', 'arrow_forward'), ('arrow_upward', 'arrow_upward'), ('art_track', 'art_track'), ('aspect_ratio', 'aspect_ratio'), ('assessment', 'assessment'), ('assignment', 'assignment'), ('assignment_ind', 'assignment_ind'), ('assignment_late', 'assignment_late'), ('assignment_return', 'assignment_return'), ('assignment_returned', 'assignment_returned'), ('assignment_turned_in', 'assignment_turned_in'), ('assistant', 'assistant'), ('assistant_photo', 'assistant_photo'), ('attach_file', 'attach_file'), ('attach_money', 'attach_money'), ('attachment', 'attachment'), ('audiotrack', 'audiotrack'), ('autorenew', 'autorenew'), ('av_timer', 'av_timer'), ('backspace', 'backspace'), ('backup', 'backup'), ('battery_alert', 'battery_alert'), ('battery_charging_full', 'battery_charging_full'), ('battery_full', 'battery_full'), ('battery_std', 'battery_std'), ('battery_unknown', 'battery_unknown'), ('beach_access', 'beach_access'), ('beenhere', 'beenhere'), ('block', 'block'), ('bluetooth', 'bluetooth'), ('bluetooth_audio', 'bluetooth_audio'), ('bluetooth_connected', 'bluetooth_connected'), ('bluetooth_disabled', 'bluetooth_disabled'), ('bluetooth_searching', 'bluetooth_searching'), ('blur_circular', 'blur_circular'), ('blur_linear', 'blur_linear'), ('blur_off', 'blur_off'), ('blur_on', 'blur_on'), ('book', 'book'), ('bookmark', 'bookmark'), ('bookmark_border', 'bookmark_border'), ('border_all', 'border_all'), ('border_bottom', 'border_bottom'), ('border_clear', 'border_clear'), ('border_color', 'border_color'), ('border_horizontal', 'border_horizontal'), ('border_inner', 'border_inner'), ('border_left', 'border_left'), ('border_outer', 'border_outer'), ('border_right', 'border_right'), ('border_style', 'border_style'), ('border_top', 'border_top'), ('border_vertical', 'border_vertical'), ('branding_watermark', 'branding_watermark'), ('brightness_1', 'brightness_1'), ('brightness_2', 'brightness_2'), ('brightness_3', 'brightness_3'), ('brightness_4', 'brightness_4'), ('brightness_5', 'brightness_5'), ('brightness_6', 'brightness_6'), ('brightness_7', 'brightness_7'), ('brightness_auto', 'brightness_auto'), ('brightness_high', 'brightness_high'), ('brightness_low', 'brightness_low'), ('brightness_medium', 'brightness_medium'), ('broken_image', 'broken_image'), ('brush', 'brush'), ('bubble_chart', 'bubble_chart'), ('bug_report', 'bug_report'), ('build', 'build'), ('burst_mode', 'burst_mode'), ('business', 'business'), ('business_center', 'business_center'), ('cached', 'cached'), ('cake', 'cake'), ('call', 'call'), ('call_end', 'call_end'), ('call_made', 'call_made'), ('call_merge', 'call_merge'), ('call_missed', 'call_missed'), ('call_missed_outgoing', 'call_missed_outgoing'), ('call_received', 'call_received'), ('call_split', 'call_split'), ('call_to_action', 'call_to_action'), ('camera', 'camera'), ('camera_alt', 'camera_alt'), ('camera_enhance', 'camera_enhance'), ('camera_front', 'camera_front'), ('camera_rear', 'camera_rear'), ('camera_roll', 'camera_roll'), ('cancel', 'cancel'), ('card_giftcard', 'card_giftcard'), ('card_membership', 'card_membership'), ('card_travel', 'card_travel'), ('casino', 'casino'), ('cast', 'cast'), ('cast_connected', 'cast_connected'), ('center_focus_strong', 'center_focus_strong'), ('center_focus_weak', 'center_focus_weak'), ('change_history', 'change_history'), ('chat', 'chat'), ('chat_bubble', 'chat_bubble'), ('chat_bubble_outline', 'chat_bubble_outline'), ('check', 'check'), ('check_box', 'check_box'), ('check_box_outline_blank', 'check_box_outline_blank'), ('check_circle', 'check_circle'), ('chevron_left', 'chevron_left'), ('chevron_right', 'chevron_right'), ('child_care', 'child_care'), ('child_friendly', 'child_friendly'), ('chrome_reader_mode', 'chrome_reader_mode'), ('class', 'class'), ('clear', 'clear'), ('clear_all', 'clear_all'), ('close', 'close'), ('closed_caption', 'closed_caption'), ('cloud', 'cloud'), ('cloud_circle', 'cloud_circle'), ('cloud_done', 'cloud_done'), ('cloud_download', 'cloud_download'), ('cloud_off', 'cloud_off'), ('cloud_queue', 'cloud_queue'), ('cloud_upload', 'cloud_upload'), ('code', 'code'), ('collections', 'collections'), ('collections_bookmark', 'collections_bookmark'), ('color_lens', 'color_lens'), ('colorize', 'colorize'), ('comment', 'comment'), ('compare', 'compare'), ('compare_arrows', 'compare_arrows'), ('computer', 'computer'), ('confirmation_number', 'confirmation_number'), ('contact_mail', 'contact_mail'), ('contact_phone', 'contact_phone'), ('contacts', 'contacts'), ('content_copy', 'content_copy'), ('content_cut', 'content_cut'), ('content_paste', 'content_paste'), ('control_point', 'control_point'), ('control_point_duplicate', 'control_point_duplicate'), ('copyright', 'copyright'), ('create', 'create'), ('create_new_folder', 'create_new_folder'), ('credit_card', 'credit_card'), ('crop', 'crop'), ('crop_16_9', 'crop_16_9'), ('crop_3_2', 'crop_3_2'), ('crop_5_4', 'crop_5_4'), ('crop_7_5', 'crop_7_5'), ('crop_din', 'crop_din'), ('crop_free', 'crop_free'), ('crop_landscape', 'crop_landscape'), ('crop_original', 'crop_original'), ('crop_portrait', 'crop_portrait'), ('crop_rotate', 'crop_rotate'), ('crop_square', 'crop_square'), ('dashboard', 'dashboard'), ('data_usage', 'data_usage'), ('date_range', 'date_range'), ('dehaze', 'dehaze'), ('delete', 'delete'), ('delete_forever', 'delete_forever'), ('delete_sweep', 'delete_sweep'), ('description', 'description'), ('desktop_mac', 'desktop_mac'), ('desktop_windows', 'desktop_windows'), ('details', 'details'), ('developer_board', 'developer_board'), ('developer_mode', 'developer_mode'), ('device_hub', 'device_hub'), ('devices', 'devices'), ('devices_other', 'devices_other'), ('dialer_sip', 'dialer_sip'), ('dialpad', 'dialpad'), ('directions', 'directions'), ('directions_bike', 'directions_bike'), ('directions_boat', 'directions_boat'), ('directions_bus', 'directions_bus'), ('directions_car', 'directions_car'), ('directions_railway', 'directions_railway'), ('directions_run', 'directions_run'), ('directions_subway', 'directions_subway'), ('directions_transit', 'directions_transit'), ('directions_walk', 'directions_walk'), ('disc_full', 'disc_full'), ('dns', 'dns'), ('do_not_disturb', 'do_not_disturb'), ('do_not_disturb_alt', 'do_not_disturb_alt'), ('do_not_disturb_off', 'do_not_disturb_off'), ('do_not_disturb_on', 'do_not_disturb_on'), ('dock', 'dock'), ('domain', 'domain'), ('done', 'done'), ('done_all', 'done_all'), ('donut_large', 'donut_large'), ('donut_small', 'donut_small'), ('drafts', 'drafts'), ('drag_handle', 'drag_handle'), ('drive_eta', 'drive_eta'), ('dvr', 'dvr'), ('edit', 'edit'), ('edit_location', 'edit_location'), ('eject', 'eject'), ('email', 'email'), ('enhanced_encryption', 'enhanced_encryption'), ('equalizer', 'equalizer'), ('error', 'error'), ('error_outline', 'error_outline'), ('euro_symbol', 'euro_symbol'), ('ev_station', 'ev_station'), ('event', 'event'), ('event_available', 'event_available'), ('event_busy', 'event_busy'), ('event_note', 'event_note'), ('event_seat', 'event_seat'), ('exit_to_app', 'exit_to_app'), ('expand_less', 'expand_less'), ('expand_more', 'expand_more'), ('explicit', 'explicit'), ('explore', 'explore'), ('exposure', 'exposure'), ('exposure_neg_1', 'exposure_neg_1'), ('exposure_neg_2', 'exposure_neg_2'), ('exposure_plus_1', 'exposure_plus_1'), ('exposure_plus_2', 'exposure_plus_2'), ('exposure_zero', 'exposure_zero'), ('extension', 'extension'), ('face', 'face'), ('fast_forward', 'fast_forward'), ('fast_rewind', 'fast_rewind'), ('favorite', 'favorite'), ('favorite_border', 'favorite_border'), ('featured_play_list', 'featured_play_list'), ('featured_video', 'featured_video'), ('feedback', 'feedback'), ('fiber_dvr', 'fiber_dvr'), ('fiber_manual_record', 'fiber_manual_record'), ('fiber_new', 'fiber_new'), ('fiber_pin', 'fiber_pin'), ('fiber_smart_record', 'fiber_smart_record'), ('file_download', 'file_download'), ('file_upload', 'file_upload'), ('filter', 'filter'), ('filter_1', 'filter_1'), ('filter_2', 'filter_2'), ('filter_3', 'filter_3'), ('filter_4', 'filter_4'), ('filter_5', 'filter_5'), ('filter_6', 'filter_6'), ('filter_7', 'filter_7'), ('filter_8', 'filter_8'), ('filter_9', 'filter_9'), ('filter_9_plus', 'filter_9_plus'), ('filter_b_and_w', 'filter_b_and_w'), ('filter_center_focus', 'filter_center_focus'), ('filter_drama', 'filter_drama'), ('filter_frames', 'filter_frames'), ('filter_hdr', 'filter_hdr'), ('filter_list', 'filter_list'), ('filter_none', 'filter_none'), ('filter_tilt_shift', 'filter_tilt_shift'), ('filter_vintage', 'filter_vintage'), ('find_in_page', 'find_in_page'), ('find_replace', 'find_replace'), ('fingerprint', 'fingerprint'), ('first_page', 'first_page'), ('fitness_center', 'fitness_center'), ('flag', 'flag'), ('flare', 'flare'), ('flash_auto', 'flash_auto'), ('flash_off', 'flash_off'), ('flash_on', 'flash_on'), ('flight', 'flight'), ('flight_land', 'flight_land'), ('flight_takeoff', 'flight_takeoff'), ('flip', 'flip'), ('flip_to_back', 'flip_to_back'), ('flip_to_front', 'flip_to_front'), ('folder', 'folder'), ('folder_open', 'folder_open'), ('folder_shared', 'folder_shared'), ('folder_special', 'folder_special'), ('font_download', 'font_download'), ('format_align_center', 'format_align_center'), ('format_align_justify', 'format_align_justify'), ('format_align_left', 'format_align_left'), ('format_align_right', 'format_align_right'), ('format_bold', 'format_bold'), ('format_clear', 'format_clear'), ('format_color_fill', 'format_color_fill'), ('format_color_reset', 'format_color_reset'), ('format_color_text', 'format_color_text'), ('format_indent_decrease', 'format_indent_decrease'), ('format_indent_increase', 'format_indent_increase'), ('format_italic', 'format_italic'), ('format_line_spacing', 'format_line_spacing'), ('format_list_bulleted', 'format_list_bulleted'), ('format_list_numbered', 'format_list_numbered'), ('format_paint', 'format_paint'), ('format_quote', 'format_quote'), ('format_shapes', 'format_shapes'), ('format_size', 'format_size'), ('format_strikethrough', 'format_strikethrough'), ('format_textdirection_l_to_r', 'format_textdirection_l_to_r'), ('format_textdirection_r_to_l', 'format_textdirection_r_to_l'), ('format_underlined', 'format_underlined'), ('forum', 'forum'), ('forward', 'forward'), ('forward_10', 'forward_10'), ('forward_30', 'forward_30'), ('forward_5', 'forward_5'), ('free_breakfast', 'free_breakfast'), ('fullscreen', 'fullscreen'), ('fullscreen_exit', 'fullscreen_exit'), ('functions', 'functions'), ('g_translate', 'g_translate'), ('gamepad', 'gamepad'), ('games', 'games'), ('gavel', 'gavel'), ('gesture', 'gesture'), ('get_app', 'get_app'), ('gif', 'gif'), ('golf_course', 'golf_course'), ('gps_fixed', 'gps_fixed'), ('gps_not_fixed', 'gps_not_fixed'), ('gps_off', 'gps_off'), ('grade', 'grade'), ('gradient', 'gradient'), ('grain', 'grain'), ('graphic_eq', 'graphic_eq'), ('grid_off', 'grid_off'), ('grid_on', 'grid_on'), ('group', 'group'), ('group_add', 'group_add'), ('group_work', 'group_work'), ('hd', 'hd'), ('hdr_off', 'hdr_off'), ('hdr_on', 'hdr_on'), ('hdr_strong', 'hdr_strong'), ('hdr_weak', 'hdr_weak'), ('headset', 'headset'), ('headset_mic', 'headset_mic'), ('healing', 'healing'), ('hearing', 'hearing'), ('help', 'help'), ('help_outline', 'help_outline'), ('high_quality', 'high_quality'), ('highlight', 'highlight'), ('highlight_off', 'highlight_off'), ('history', 'history'), ('home', 'home'), ('hot_tub', 'hot_tub'), ('hotel', 'hotel'), ('hourglass_empty', 'hourglass_empty'), ('hourglass_full', 'hourglass_full'), ('http', 'http'), ('https', 'https'), ('image', 'image'), ('image_aspect_ratio', 'image_aspect_ratio'), ('import_contacts', 'import_contacts'), ('import_export', 'import_export'), ('important_devices', 'important_devices'), ('inbox', 'inbox'), ('indeterminate_check_box', 'indeterminate_check_box'), ('info', 'info'), ('info_outline', 'info_outline'), ('input', 'input'), ('insert_chart', 'insert_chart'), ('insert_comment', 'insert_comment'), ('insert_drive_file', 'insert_drive_file'), ('insert_emoticon', 'insert_emoticon'), ('insert_invitation', 'insert_invitation'), ('insert_link', 'insert_link'), ('insert_photo', 'insert_photo'), ('invert_colors', 'invert_colors'), ('invert_colors_off', 'invert_colors_off'), ('iso', 'iso'), ('keyboard', 'keyboard'), ('keyboard_arrow_down', 'keyboard_arrow_down'), ('keyboard_arrow_left', 'keyboard_arrow_left'), ('keyboard_arrow_right', 'keyboard_arrow_right'), ('keyboard_arrow_up', 'keyboard_arrow_up'), ('keyboard_backspace', 'keyboard_backspace'), ('keyboard_capslock', 'keyboard_capslock'), ('keyboard_hide', 'keyboard_hide'), ('keyboard_return', 'keyboard_return'), ('keyboard_tab', 'keyboard_tab'), ('keyboard_voice', 'keyboard_voice'), ('kitchen', 'kitchen'), ('label', 'label'), ('label_outline', 'label_outline'), ('landscape', 'landscape'), ('language', 'language'), ('laptop', 'laptop'), ('laptop_chromebook', 'laptop_chromebook'), ('laptop_mac', 'laptop_mac'), ('laptop_windows', 'laptop_windows'), ('last_page', 'last_page'), ('launch', 'launch'), ('layers', 'layers'), ('layers_clear', 'layers_clear'), ('leak_add', 'leak_add'), ('leak_remove', 'leak_remove'), ('lens', 'lens'), ('library_add', 'library_add'), ('library_books', 'library_books'), ('library_music', 'library_music'), ('lightbulb_outline', 'lightbulb_outline'), ('line_style', 'line_style'), ('line_weight', 'line_weight'), ('linear_scale', 'linear_scale'), ('link', 'link'), ('linked_camera', 'linked_camera'), ('list', 'list'), ('live_help', 'live_help'), ('live_tv', 'live_tv'), ('local_activity', 'local_activity'), ('local_airport', 'local_airport'), ('local_atm', 'local_atm'), ('local_bar', 'local_bar'), ('local_cafe', 'local_cafe'), ('local_car_wash', 'local_car_wash'), ('local_convenience_store', 'local_convenience_store'), ('local_dining', 'local_dining'), ('local_drink', 'local_drink'), ('local_florist', 'local_florist'), ('local_gas_station', 'local_gas_station'), ('local_grocery_store', 'local_grocery_store'), ('local_hospital', 'local_hospital'), ('local_hotel', 'local_hotel'), ('local_laundry_service', 'local_laundry_service'), ('local_library', 'local_library'), ('local_mall', 'local_mall'), ('local_movies', 'local_movies'), ('local_offer', 'local_offer'), ('local_parking', 'local_parking'), ('local_pharmacy', 'local_pharmacy'), ('local_phone', 'local_phone'), ('local_pizza', 'local_pizza'), ('local_play', 'local_play'), ('local_post_office', 'local_post_office'), ('local_printshop', 'local_printshop'), ('local_see', 'local_see'), ('local_shipping', 'local_shipping'), ('local_taxi', 'local_taxi'), ('location_city', 'location_city'), ('location_disabled', 'location_disabled'), ('location_off', 'location_off'), ('location_on', 'location_on'), ('location_searching', 'location_searching'), ('lock', 'lock'), ('lock_open', 'lock_open'), ('lock_outline', 'lock_outline'), ('looks', 'looks'), ('looks_3', 'looks_3'), ('looks_4', 'looks_4'), ('looks_5', 'looks_5'), ('looks_6', 'looks_6'), ('looks_one', 'looks_one'), ('looks_two', 'looks_two'), ('loop', 'loop'), ('loupe', 'loupe'), ('low_priority', 'low_priority'), ('loyalty', 'loyalty'), ('mail', 'mail'), ('mail_outline', 'mail_outline'), ('map', 'map'), ('markunread', 'markunread'), ('markunread_mailbox', 'markunread_mailbox'), ('memory', 'memory'), ('menu', 'menu'), ('merge_type', 'merge_type'), ('message', 'message'), ('mic', 'mic'), ('mic_none', 'mic_none'), ('mic_off', 'mic_off'), ('mms', 'mms'), ('mode_comment', 'mode_comment'), ('mode_edit', 'mode_edit'), ('monetization_on', 'monetization_on'), ('money_off', 'money_off'), ('monochrome_photos', 'monochrome_photos'), ('mood', 'mood'), ('mood_bad', 'mood_bad'), ('more', 'more'), ('more_horiz', 'more_horiz'), ('more_vert', 'more_vert'), ('motorcycle', 'motorcycle'), ('mouse', 'mouse'), ('move_to_inbox', 'move_to_inbox'), ('movie', 'movie'), ('movie_creation', 'movie_creation'), ('movie_filter', 'movie_filter'), ('multiline_chart', 'multiline_chart'), ('music_note', 'music_note'), ('music_video', 'music_video'), ('my_location', 'my_location'), ('nature', 'nature'), ('nature_people', 'nature_people'), ('navigate_before', 'navigate_before'), ('navigate_next', 'navigate_next'), ('navigation', 'navigation'), ('near_me', 'near_me'), ('network_cell', 'network_cell'), ('network_check', 'network_check'), ('network_locked', 'network_locked'), ('network_wifi', 'network_wifi'), ('new_releases', 'new_releases'), ('next_week', 'next_week'), ('nfc', 'nfc'), ('no_encryption', 'no_encryption'), ('no_sim', 'no_sim'), ('not_interested', 'not_interested'), ('note', 'note'), ('note_add', 'note_add'), ('notifications', 'notifications'), ('notifications_active', 'notifications_active'), ('notifications_none', 'notifications_none'), ('notifications_off', 'notifications_off'), ('notifications_paused', 'notifications_paused'), ('offline_pin', 'offline_pin'), ('ondemand_video', 'ondemand_video'), ('opacity', 'opacity'), ('open_in_browser', 'open_in_browser'), ('open_in_new', 'open_in_new'), ('open_with', 'open_with'), ('pages', 'pages'), ('pageview', 'pageview'), ('palette', 'palette'), ('pan_tool', 'pan_tool'), ('panorama', 'panorama'), ('panorama_fish_eye', 'panorama_fish_eye'), ('panorama_horizontal', 'panorama_horizontal'), ('panorama_vertical', 'panorama_vertical'), ('panorama_wide_angle', 'panorama_wide_angle'), ('party_mode', 'party_mode'), ('pause', 'pause'), ('pause_circle_filled', 'pause_circle_filled'), ('pause_circle_outline', 'pause_circle_outline'), ('payment', 'payment'), ('people', 'people'), ('people_outline', 'people_outline'), ('perm_camera_mic', 'perm_camera_mic'), ('perm_contact_calendar', 'perm_contact_calendar'), ('perm_data_setting', 'perm_data_setting'), ('perm_device_information', 'perm_device_information'), ('perm_identity', 'perm_identity'), ('perm_media', 'perm_media'), ('perm_phone_msg', 'perm_phone_msg'), ('perm_scan_wifi', 'perm_scan_wifi'), ('person', 'person'), ('person_add', 'person_add'), ('person_outline', 'person_outline'), ('person_pin', 'person_pin'), ('person_pin_circle', 'person_pin_circle'), ('personal_video', 'personal_video'), ('pets', 'pets'), ('phone', 'phone'), ('phone_android', 'phone_android'), ('phone_bluetooth_speaker', 'phone_bluetooth_speaker'), ('phone_forwarded', 'phone_forwarded'), ('phone_in_talk', 'phone_in_talk'), ('phone_iphone', 'phone_iphone'), ('phone_locked', 'phone_locked'), ('phone_missed', 'phone_missed'), ('phone_paused', 'phone_paused'), ('phonelink', 'phonelink'), ('phonelink_erase', 'phonelink_erase'), ('phonelink_lock', 'phonelink_lock'), ('phonelink_off', 'phonelink_off'), ('phonelink_ring', 'phonelink_ring'), ('phonelink_setup', 'phonelink_setup'), ('photo', 'photo'), ('photo_album', 'photo_album'), ('photo_camera', 'photo_camera'), ('photo_filter', 'photo_filter'), ('photo_library', 'photo_library'), ('photo_size_select_actual', 'photo_size_select_actual'), ('photo_size_select_large', 'photo_size_select_large'), ('photo_size_select_small', 'photo_size_select_small'), ('picture_as_pdf', 'picture_as_pdf'), ('picture_in_picture', 'picture_in_picture'), ('picture_in_picture_alt', 'picture_in_picture_alt'), ('pie_chart', 'pie_chart'), ('pie_chart_outlined', 'pie_chart_outlined'), ('pin_drop', 'pin_drop'), ('place', 'place'), ('play_arrow', 'play_arrow'), ('play_circle_filled', 'play_circle_filled'), ('play_circle_outline', 'play_circle_outline'), ('play_for_work', 'play_for_work'), ('playlist_add', 'playlist_add'), ('playlist_add_check', 'playlist_add_check'), ('playlist_play', 'playlist_play'), ('plus_one', 'plus_one'), ('poll', 'poll'), ('polymer', 'polymer'), ('pool', 'pool'), ('portable_wifi_off', 'portable_wifi_off'), ('portrait', 'portrait'), ('power', 'power'), ('power_input', 'power_input'), ('power_settings_new', 'power_settings_new'), ('pregnant_woman', 'pregnant_woman'), ('present_to_all', 'present_to_all'), ('print', 'print'), ('priority_high', 'priority_high'), ('public', 'public'), ('publish', 'publish'), ('query_builder', 'query_builder'), ('question_answer', 'question_answer'), ('queue', 'queue'), ('queue_music', 'queue_music'), ('queue_play_next', 'queue_play_next'), ('radio', 'radio'), ('radio_button_checked', 'radio_button_checked'), ('radio_button_unchecked', 'radio_button_unchecked'), ('rate_review', 'rate_review'), ('receipt', 'receipt'), ('recent_actors', 'recent_actors'), ('record_voice_over', 'record_voice_over'), ('redeem', 'redeem'), ('redo', 'redo'), ('refresh', 'refresh'), ('remove', 'remove'), ('remove_circle', 'remove_circle'), ('remove_circle_outline', 'remove_circle_outline'), ('remove_from_queue', 'remove_from_queue'), ('remove_red_eye', 'remove_red_eye'), ('remove_shopping_cart', 'remove_shopping_cart'), ('reorder', 'reorder'), ('repeat', 'repeat'), ('repeat_one', 'repeat_one'), ('replay', 'replay'), ('replay_10', 'replay_10'), ('replay_30', 'replay_30'), ('replay_5', 'replay_5'), ('reply', 'reply'), ('reply_all', 'reply_all'), ('report', 'report'), ('report_problem', 'report_problem'), ('restaurant', 'restaurant'), ('restaurant_menu', 'restaurant_menu'), ('restore', 'restore'), ('restore_page', 'restore_page'), ('ring_volume', 'ring_volume'), ('room', 'room'), ('room_service', 'room_service'), ('rotate_90_degrees_ccw', 'rotate_90_degrees_ccw'), ('rotate_left', 'rotate_left'), ('rotate_right', 'rotate_right'), ('rounded_corner', 'rounded_corner'), ('router', 'router'), ('rowing', 'rowing'), ('rss_feed', 'rss_feed'), ('rv_hookup', 'rv_hookup'), ('satellite', 'satellite'), ('save', 'save'), ('scanner', 'scanner'), ('schedule', 'schedule'), ('school', 'school'), ('screen_lock_landscape', 'screen_lock_landscape'), ('screen_lock_portrait', 'screen_lock_portrait'), ('screen_lock_rotation', 'screen_lock_rotation'), ('screen_rotation', 'screen_rotation'), ('screen_share', 'screen_share'), ('sd_card', 'sd_card'), ('sd_storage', 'sd_storage'), ('search', 'search'), ('security', 'security'), ('select_all', 'select_all'), ('send', 'send'), ('sentiment_dissatisfied', 'sentiment_dissatisfied'), ('sentiment_neutral', 'sentiment_neutral'), ('sentiment_satisfied', 'sentiment_satisfied'), ('sentiment_very_dissatisfied', 'sentiment_very_dissatisfied'), ('sentiment_very_satisfied', 'sentiment_very_satisfied'), ('settings', 'settings'), ('settings_applications', 'settings_applications'), ('settings_backup_restore', 'settings_backup_restore'), ('settings_bluetooth', 'settings_bluetooth'), ('settings_brightness', 'settings_brightness'), ('settings_cell', 'settings_cell'), ('settings_ethernet', 'settings_ethernet'), ('settings_input_antenna', 'settings_input_antenna'), ('settings_input_component', 'settings_input_component'), ('settings_input_composite', 'settings_input_composite'), ('settings_input_hdmi', 'settings_input_hdmi'), ('settings_input_svideo', 'settings_input_svideo'), ('settings_overscan', 'settings_overscan'), ('settings_phone', 'settings_phone'), ('settings_power', 'settings_power'), ('settings_remote', 'settings_remote'), ('settings_system_daydream', 'settings_system_daydream'), ('settings_voice', 'settings_voice'), ('share', 'share'), ('shop', 'shop'), ('shop_two', 'shop_two'), ('shopping_basket', 'shopping_basket'), ('shopping_cart', 'shopping_cart'), ('short_text', 'short_text'), ('show_chart', 'show_chart'), ('shuffle', 'shuffle'), ('signal_cellular_4_bar', 'signal_cellular_4_bar'), ('signal_cellular_connected_no_internet_4_bar', 'signal_cellular_connected_no_internet_4_bar'), ('signal_cellular_no_sim', 'signal_cellular_no_sim'), ('signal_cellular_null', 'signal_cellular_null'), ('signal_cellular_off', 'signal_cellular_off'), ('signal_wifi_4_bar', 'signal_wifi_4_bar'), ('signal_wifi_4_bar_lock', 'signal_wifi_4_bar_lock'), ('signal_wifi_off', 'signal_wifi_off'), ('sim_card', 'sim_card'), ('sim_card_alert', 'sim_card_alert'), ('skip_next', 'skip_next'), ('skip_previous', 'skip_previous'), ('slideshow', 'slideshow'), ('slow_motion_video', 'slow_motion_video'), ('smartphone', 'smartphone'), ('smoke_free', 'smoke_free'), ('smoking_rooms', 'smoking_rooms'), ('sms', 'sms'), ('sms_failed', 'sms_failed'), ('snooze', 'snooze'), ('sort', 'sort'), ('sort_by_alpha', 'sort_by_alpha'), ('spa', 'spa'), ('space_bar', 'space_bar'), ('speaker', 'speaker'), ('speaker_group', 'speaker_group'), ('speaker_notes', 'speaker_notes'), ('speaker_notes_off', 'speaker_notes_off'), ('speaker_phone', 'speaker_phone'), ('spellcheck', 'spellcheck'), ('star', 'star'), ('star_border', 'star_border'), ('star_half', 'star_half'), ('stars', 'stars'), ('stay_current_landscape', 'stay_current_landscape'), ('stay_current_portrait', 'stay_current_portrait'), ('stay_primary_landscape', 'stay_primary_landscape'), ('stay_primary_portrait', 'stay_primary_portrait'), ('stop', 'stop'), ('stop_screen_share', 'stop_screen_share'), ('storage', 'storage'), ('store', 'store'), ('store_mall_directory', 'store_mall_directory'), ('straighten', 'straighten'), ('streetview', 'streetview'), ('strikethrough_s', 'strikethrough_s'), ('style', 'style'), ('subdirectory_arrow_left', 'subdirectory_arrow_left'), ('subdirectory_arrow_right', 'subdirectory_arrow_right'), ('subject', 'subject'), ('subscriptions', 'subscriptions'), ('subtitles', 'subtitles'), ('subway', 'subway'), ('supervisor_account', 'supervisor_account'), ('surround_sound', 'surround_sound'), ('swap_calls', 'swap_calls'), ('swap_horiz', 'swap_horiz'), ('swap_vert', 'swap_vert'), ('swap_vertical_circle', 'swap_vertical_circle'), ('switch_camera', 'switch_camera'), ('switch_video', 'switch_video'), ('sync', 'sync'), ('sync_disabled', 'sync_disabled'), ('sync_problem', 'sync_problem'), ('system_update', 'system_update'), ('system_update_alt', 'system_update_alt'), ('tab', 'tab'), ('tab_unselected', 'tab_unselected'), ('tablet', 'tablet'), ('tablet_android', 'tablet_android'), ('tablet_mac', 'tablet_mac'), ('tag_faces', 'tag_faces'), ('tap_and_play', 'tap_and_play'), ('terrain', 'terrain'), ('text_fields', 'text_fields'), ('text_format', 'text_format'), ('textsms', 'textsms'), ('texture', 'texture'), ('theaters', 'theaters'), ('thumb_down', 'thumb_down'), ('thumb_up', 'thumb_up'), ('thumbs_up_down', 'thumbs_up_down'), ('time_to_leave', 'time_to_leave'), ('timelapse', 'timelapse'), ('timeline', 'timeline'), ('timer', 'timer'), ('timer_10', 'timer_10'), ('timer_3', 'timer_3'), ('timer_off', 'timer_off'), ('title', 'title'), ('toc', 'toc'), ('today', 'today'), ('toll', 'toll'), ('tonality', 'tonality'), ('touch_app', 'touch_app'), ('toys', 'toys'), ('track_changes', 'track_changes'), ('traffic', 'traffic'), ('train', 'train'), ('tram', 'tram'), ('transfer_within_a_station', 'transfer_within_a_station'), ('transform', 'transform'), ('translate', 'translate'), ('trending_down', 'trending_down'), ('trending_flat', 'trending_flat'), ('trending_up', 'trending_up'), ('tune', 'tune'), ('turned_in', 'turned_in'), ('turned_in_not', 'turned_in_not'), ('tv', 'tv'), ('unarchive', 'unarchive'), ('undo', 'undo'), ('unfold_less', 'unfold_less'), ('unfold_more', 'unfold_more'), ('update', 'update'), ('usb', 'usb'), ('verified_user', 'verified_user'), ('vertical_align_bottom', 'vertical_align_bottom'), ('vertical_align_center', 'vertical_align_center'), ('vertical_align_top', 'vertical_align_top'), ('vibration', 'vibration'), ('video_call', 'video_call'), ('video_label', 'video_label'), ('video_library', 'video_library'), ('videocam', 'videocam'), ('videocam_off', 'videocam_off'), ('videogame_asset', 'videogame_asset'), ('view_agenda', 'view_agenda'), ('view_array', 'view_array'), ('view_carousel', 'view_carousel'), ('view_column', 'view_column'), ('view_comfy', 'view_comfy'), ('view_compact', 'view_compact'), ('view_day', 'view_day'), ('view_headline', 'view_headline'), ('view_list', 'view_list'), ('view_module', 'view_module'), ('view_quilt', 'view_quilt'), ('view_stream', 'view_stream'), ('view_week', 'view_week'), ('vignette', 'vignette'), ('visibility', 'visibility'), ('visibility_off', 'visibility_off'), ('voice_chat', 'voice_chat'), ('voicemail', 'voicemail'), ('volume_down', 'volume_down'), ('volume_mute', 'volume_mute'), ('volume_off', 'volume_off'), ('volume_up', 'volume_up'), ('vpn_key', 'vpn_key'), ('vpn_lock', 'vpn_lock'), ('wallpaper', 'wallpaper'), ('warning', 'warning'), ('watch', 'watch'), ('watch_later', 'watch_later'), ('wb_auto', 'wb_auto'), ('wb_cloudy', 'wb_cloudy'), ('wb_incandescent', 'wb_incandescent'), ('wb_iridescent', 'wb_iridescent'), ('wb_sunny', 'wb_sunny'), ('wc', 'wc'), ('web', 'web'), ('web_asset', 'web_asset'), ('weekend', 'weekend'), ('whatshot', 'whatshot'), ('widgets', 'widgets'), ('wifi', 'wifi'), ('wifi_lock', 'wifi_lock'), ('wifi_tethering', 'wifi_tethering'), ('work', 'work'), ('wrap_text', 'wrap_text'), ('youtube_searched_for', 'youtube_searched_for'), ('zoom_in', 'zoom_in'), ('zoom_out', 'zoom_out'), ('zoom_out_map', 'zoom_out_map')], max_length=50, verbose_name='Icon')),
+                ('pdf_file', models.FileField(upload_to='instructions/', validators=[django.core.validators.FileExtensionValidator(['pdf'])], verbose_name='PDF file')),
+                ('groups', models.ManyToManyField(blank=True, help_text='The instruction will be shown for the members and owners of the selected groups.', null=True, to='core.Group', verbose_name='Groups')),
+                ('school_term', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='core.schoolterm', verbose_name='Linked school term')),
+                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.site')),
+            ],
+            options={
+                'verbose_name': 'Instruction',
+                'verbose_name_plural': 'Instructions',
+            },
+        ),
+        migrations.AddConstraint(
+            model_name='instruction',
+            constraint=models.UniqueConstraint(fields=('site_id', 'name', 'school_term'), name='site_name_school_term_unique'),
+        ),
+    ]
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 51857750b..8d387dbee 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -2,6 +2,7 @@ from datetime import date
 from typing import Optional, Union
 from urllib.parse import urlparse
 
+from django.core.validators import FileExtensionValidator
 from django.db import models
 from django.db.models.constraints import CheckConstraint
 from django.db.models.query_utils import Q
@@ -31,8 +32,12 @@ from aleksis.apps.alsijil.managers import (
 from aleksis.apps.chronos.managers import GroupPropertiesMixin
 from aleksis.apps.chronos.mixins import WeekRelatedMixin
 from aleksis.apps.chronos.models import Event, ExtraLesson, LessonPeriod, TimePeriod
-from aleksis.core.mixins import ExtensibleModel, GlobalPermissionModel
-from aleksis.core.models import SchoolTerm
+from aleksis.core.mixins import (
+    ExtensibleModel,
+    GlobalPermissionModel,
+    SchoolTermRelatedExtensibleModel,
+)
+from aleksis.core.models import Group, SchoolTerm
 from aleksis.core.util.core_helpers import get_site_preferences
 from aleksis.core.util.model_helpers import ICONS
 
@@ -467,6 +472,34 @@ class GroupRoleAssignment(GroupPropertiesMixin, ExtensibleModel):
         verbose_name_plural = _("Group role assignments")
 
 
+class Instruction(SchoolTermRelatedExtensibleModel):
+    name = models.CharField(max_length=255, verbose_name=_("Name"))
+    icon = models.CharField(max_length=50, blank=True, choices=ICONS, verbose_name=_("Icon"))
+    pdf_file = models.FileField(
+        upload_to="instructions/",
+        verbose_name=_("PDF file"),
+        validators=[FileExtensionValidator(["pdf"])],
+    )
+    groups = models.ManyToManyField(
+        to=Group,
+        blank=True,
+        null=True,
+        verbose_name=_("Groups"),
+        help_text=_(
+            "The instruction will be shown for the members and owners of the selected groups."
+        ),
+    )
+
+    class Meta:
+        verbose_name = _("Instruction")
+        verbose_name_plural = _("Instructions")
+        constraints = [
+            models.UniqueConstraint(
+                fields=["site_id", "name", "school_term"], name="site_name_school_term_unique"
+            )
+        ]
+
+
 class AlsijilGlobalPermissions(GlobalPermissionModel):
     class Meta:
         managed = False
-- 
GitLab