diff --git a/cms/djangoapps/contentstore/management/commands/sync_courses.py b/cms/djangoapps/contentstore/management/commands/sync_courses.py index ad0b9a5e8e..47cf557608 100644 --- a/cms/djangoapps/contentstore/management/commands/sync_courses.py +++ b/cms/djangoapps/contentstore/management/commands/sync_courses.py @@ -3,17 +3,18 @@ Sync courses from catalog service. This is used to setup a master's integration environment. """ import logging -from six import text_type +from textwrap import dedent from django.contrib.auth.models import User from django.core.management.base import BaseCommand, CommandError +from opaque_keys.edx.keys import CourseKey +from six import text_type from contentstore.management.commands.utils import user_from_str from contentstore.views.course import create_new_course_in_store -from opaque_keys.edx.keys import CourseKey from openedx.core.djangoapps.catalog.utils import get_course_runs -from xmodule.modulestore.exceptions import DuplicateCourseError from xmodule.modulestore import ModuleStoreEnum +from xmodule.modulestore.exceptions import DuplicateCourseError logger = logging.getLogger(__name__) @@ -24,6 +25,7 @@ class Command(BaseCommand): Example: ./manage.py cms sync_courses staff@example.com """ + help = dedent(__doc__).strip() def add_arguments(self, parser): parser.add_argument('instructor') diff --git a/common/djangoapps/entitlements/management/commands/expire_old_entitlements.py b/common/djangoapps/entitlements/management/commands/expire_old_entitlements.py index 9e9cbe3855..7749afc7cb 100644 --- a/common/djangoapps/entitlements/management/commands/expire_old_entitlements.py +++ b/common/djangoapps/entitlements/management/commands/expire_old_entitlements.py @@ -5,6 +5,7 @@ Management command for expiring old entitlements. from __future__ import absolute_import import logging +from textwrap import dedent from django.core.management import BaseCommand from six.moves import range @@ -28,7 +29,7 @@ class Command(BaseCommand): The command's goal is to pass a narrow subset of entitlements to an idempotent Celery task for further (parallelized) processing. """ - help = 'Expire old entitlements.' + help = dedent(__doc__).strip() def add_arguments(self, parser): parser.add_argument( diff --git a/common/djangoapps/student/management/commands/populate_created_on_site_user_attribute.py b/common/djangoapps/student/management/commands/populate_created_on_site_user_attribute.py index 1a5345ec3a..1ea49a42c1 100644 --- a/common/djangoapps/student/management/commands/populate_created_on_site_user_attribute.py +++ b/common/djangoapps/student/management/commands/populate_created_on_site_user_attribute.py @@ -3,13 +3,12 @@ Command to back-populate domain of the site the user account was created on. """ from __future__ import absolute_import +import six from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.core.management.base import BaseCommand, CommandError from student.models import Registration, UserAttribute -import six - CREATED_ON_SITE = 'created_on_site' @@ -18,7 +17,8 @@ class Command(BaseCommand): """ This command back-populates domain of the site the user account was created on. """ - help = """./manage.py lms populate_created_on_site_user_attribute --users ,... + help = """This command back-populates domain of the site the user account was created on. + Example: ./manage.py lms populate_created_on_site_user_attribute --users ,... '--activation-keys ,... --site-domain --settings=devstack_docker""" def add_arguments(self, parser): diff --git a/common/djangoapps/track/management/commands/tracked_dummy_command.py b/common/djangoapps/track/management/commands/tracked_dummy_command.py index 8de8e0bc64..092ad30d3b 100644 --- a/common/djangoapps/track/management/commands/tracked_dummy_command.py +++ b/common/djangoapps/track/management/commands/tracked_dummy_command.py @@ -5,6 +5,7 @@ Command used for testing TrackedCommands from __future__ import absolute_import import json +from textwrap import dedent from eventtracking import tracker as eventtracker @@ -13,6 +14,8 @@ from track.management.tracked_command import TrackedCommand class Command(TrackedCommand): """A locally-defined command, for testing, that returns the current context as a JSON string.""" + help = dedent(__doc__).strip() + def add_arguments(self, parser): parser.add_argument('dummy_arg') parser.add_argument('--key1') diff --git a/lms/djangoapps/certificates/management/commands/create_fake_cert.py b/lms/djangoapps/certificates/management/commands/create_fake_cert.py index 98ad84b591..fb6c66c6f7 100644 --- a/lms/djangoapps/certificates/management/commands/create_fake_cert.py +++ b/lms/djangoapps/certificates/management/commands/create_fake_cert.py @@ -12,6 +12,7 @@ Example usage: from __future__ import absolute_import import logging +from textwrap import dedent from django.contrib.auth.models import User from django.core.management.base import BaseCommand @@ -25,6 +26,7 @@ LOGGER = logging.getLogger(__name__) class Command(BaseCommand): """Create a fake certificate for a user in a course. """ + help = dedent(__doc__).strip() def add_arguments(self, parser): parser.add_argument( diff --git a/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py b/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py index e7519e8a32..f11a6422cb 100644 --- a/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py +++ b/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py @@ -19,6 +19,7 @@ Example usage: from __future__ import absolute_import import logging +from textwrap import dedent from django.core.management.base import BaseCommand, CommandError from opaque_keys import InvalidKeyError @@ -34,6 +35,7 @@ LOGGER = logging.getLogger(__name__) class Command(BaseCommand): """Resubmit certificates with error status. """ + help = dedent(__doc__).strip() def add_arguments(self, parser): parser.add_argument( diff --git a/lms/djangoapps/instructor_task/management/commands/fail_old_tasks.py b/lms/djangoapps/instructor_task/management/commands/fail_old_tasks.py index 526f12cb62..dca6ac783f 100644 --- a/lms/djangoapps/instructor_task/management/commands/fail_old_tasks.py +++ b/lms/djangoapps/instructor_task/management/commands/fail_old_tasks.py @@ -4,6 +4,7 @@ Commands to fail old tasks from __future__ import absolute_import, print_function, unicode_literals from datetime import datetime +from textwrap import dedent from celery.states import FAILURE from django.core.management.base import BaseCommand, CommandError @@ -21,6 +22,7 @@ class Command(BaseCommand): ./manage.py lms fail_old_tasks QUEUING --dry-run --after 2001-01-03 \ --before 2001-01-06 --task-type bulk_course_email """ + help = dedent(__doc__).strip() def add_arguments(self, parser): """ diff --git a/lms/djangoapps/program_enrollments/management/commands/reset_enrollment_data.py b/lms/djangoapps/program_enrollments/management/commands/reset_enrollment_data.py index 95dc3c2896..1f9a029f62 100644 --- a/lms/djangoapps/program_enrollments/management/commands/reset_enrollment_data.py +++ b/lms/djangoapps/program_enrollments/management/commands/reset_enrollment_data.py @@ -7,6 +7,7 @@ Intented for use in integration sandbox environments from __future__ import absolute_import import logging +from textwrap import dedent from django.core.management.base import BaseCommand, CommandError from django.db import transaction @@ -25,6 +26,7 @@ class Command(BaseCommand): Example usage: $ ./manage.py lms reset_enrollment_data ca73b4af-676a-4bb3-a9a5-f6b5a3dedd,1c5f61b9-0be5-4a90-9ea5-582d5e066c """ + help = dedent(__doc__).strip() confirmation_prompt = "Type 'confirm' to continue with deletion\n" def add_arguments(self, parser): diff --git a/openedx/core/djangoapps/coursegraph/management/commands/dump_to_neo4j.py b/openedx/core/djangoapps/coursegraph/management/commands/dump_to_neo4j.py index 47b1cc5b5d..76009429ce 100644 --- a/openedx/core/djangoapps/coursegraph/management/commands/dump_to_neo4j.py +++ b/openedx/core/djangoapps/coursegraph/management/commands/dump_to_neo4j.py @@ -5,6 +5,7 @@ neo4j, a graph database. from __future__ import absolute_import, print_function, unicode_literals import logging +from textwrap import dedent from django.core.management.base import BaseCommand from django.utils import six @@ -35,6 +36,8 @@ class Command(BaseCommand): python manage.py lms dump_to_neo4j --host localhost --https_port 7473 \ --secure --user user --password password --settings=production """ + help = dedent(__doc__).strip() + def add_arguments(self, parser): parser.add_argument('--host', type=six.text_type) parser.add_argument('--https_port', type=int, default=7473) diff --git a/openedx/core/djangoapps/schedules/management/commands/send_course_update.py b/openedx/core/djangoapps/schedules/management/commands/send_course_update.py index c55be1055b..3497608eb4 100644 --- a/openedx/core/djangoapps/schedules/management/commands/send_course_update.py +++ b/openedx/core/djangoapps/schedules/management/commands/send_course_update.py @@ -3,6 +3,8 @@ Management command to send Schedule course updates """ from __future__ import absolute_import +from textwrap import dedent + from six.moves import range from openedx.core.djangoapps.schedules.management.commands import SendEmailBaseCommand @@ -10,6 +12,10 @@ from openedx.core.djangoapps.schedules.tasks import ScheduleCourseUpdate class Command(SendEmailBaseCommand): + """ + Command to send Schedule course updates + """ + help = dedent(__doc__).strip() async_send_task = ScheduleCourseUpdate log_prefix = 'Course Update' offsets = range(-7, -77, -7) diff --git a/openedx/core/djangoapps/schedules/management/commands/send_recurring_nudge.py b/openedx/core/djangoapps/schedules/management/commands/send_recurring_nudge.py index e1506e7a8e..a6cc461fd8 100644 --- a/openedx/core/djangoapps/schedules/management/commands/send_recurring_nudge.py +++ b/openedx/core/djangoapps/schedules/management/commands/send_recurring_nudge.py @@ -3,11 +3,17 @@ Management command to send recurring Schedule nudges """ from __future__ import absolute_import +from textwrap import dedent + from openedx.core.djangoapps.schedules.management.commands import SendEmailBaseCommand from openedx.core.djangoapps.schedules.tasks import ScheduleRecurringNudge class Command(SendEmailBaseCommand): + """ + Command to send recurring Schedule nudges + """ + help = dedent(__doc__).strip() async_send_task = ScheduleRecurringNudge log_prefix = 'Scheduled Nudge' offsets = (-3, -10) diff --git a/openedx/core/djangoapps/schedules/management/commands/send_upgrade_reminder.py b/openedx/core/djangoapps/schedules/management/commands/send_upgrade_reminder.py index b36643cc9b..4c973abf33 100644 --- a/openedx/core/djangoapps/schedules/management/commands/send_upgrade_reminder.py +++ b/openedx/core/djangoapps/schedules/management/commands/send_upgrade_reminder.py @@ -3,11 +3,17 @@ A management command to send Schedule upgrade reminders """ from __future__ import absolute_import +from textwrap import dedent + from openedx.core.djangoapps.schedules.management.commands import SendEmailBaseCommand from openedx.core.djangoapps.schedules.tasks import ScheduleUpgradeReminder class Command(SendEmailBaseCommand): + """ + A management command to send Schedule upgrade reminders + """ + help = dedent(__doc__).strip() async_send_task = ScheduleUpgradeReminder log_prefix = 'Upgrade Reminder' offsets = (2,) diff --git a/openedx/core/djangoapps/schedules/management/commands/setup_models_to_send_test_emails.py b/openedx/core/djangoapps/schedules/management/commands/setup_models_to_send_test_emails.py index 4a1bfefab1..9d2eac6612 100644 --- a/openedx/core/djangoapps/schedules/management/commands/setup_models_to_send_test_emails.py +++ b/openedx/core/djangoapps/schedules/management/commands/setup_models_to_send_test_emails.py @@ -5,6 +5,7 @@ A managment command that can be used to set up Schedules with various configurat from __future__ import absolute_import import datetime +from textwrap import dedent import factory import pytz @@ -57,6 +58,7 @@ class Command(BaseCommand): A management command that generates schedule objects for all expected schedule email types, so that it is easy to generate test emails of all available types. """ + help = dedent(__doc__).strip() def handle(self, *args, **options): courses = modulestore().get_courses() diff --git a/openedx/core/djangoapps/site_configuration/management/commands/create_site_configuration.py b/openedx/core/djangoapps/site_configuration/management/commands/create_site_configuration.py index 06f0512583..c35ba87c78 100644 --- a/openedx/core/djangoapps/site_configuration/management/commands/create_site_configuration.py +++ b/openedx/core/djangoapps/site_configuration/management/commands/create_site_configuration.py @@ -3,9 +3,11 @@ Run by ansible to setup a single site configuration in sandbox environments """ import json import logging +from textwrap import dedent from django.contrib.sites.models import Site from django.core.management.base import BaseCommand + from openedx.core.djangoapps.site_configuration.models import SiteConfiguration LOG = logging.getLogger(__name__) @@ -20,6 +22,8 @@ class Command(BaseCommand): ./manage.py lms create_configuration uox.sandbox.edx.org --configuration="{'COURSE_CATALOG_API_URL':'https://discovery-uox.sandbox.edx.org/api/v1'}" """ + help = dedent(__doc__).strip() + def add_arguments(self, parser): parser.add_argument('domain') parser.add_argument( diff --git a/openedx/core/djangoapps/theming/management/commands/create_sites_and_configurations.py b/openedx/core/djangoapps/theming/management/commands/create_sites_and_configurations.py index 00cd7b2a02..108dfa850b 100644 --- a/openedx/core/djangoapps/theming/management/commands/create_sites_and_configurations.py +++ b/openedx/core/djangoapps/theming/management/commands/create_sites_and_configurations.py @@ -8,6 +8,7 @@ import fnmatch import json import logging import os +from textwrap import dedent from django.contrib.auth.models import User from django.contrib.sites.models import Site @@ -31,6 +32,7 @@ class Command(BaseCommand): Example: ./manage.py lms create_sites_and_configurations --dns-name whitelabel --theme-path /edx/src/edx-themes/edx-platform """ + help = dedent(__doc__).strip() dns_name = None theme_path = None ecommerce_user = None diff --git a/openedx/core/djangoapps/user_api/management/commands/bulk_user_org_email_optout.py b/openedx/core/djangoapps/user_api/management/commands/bulk_user_org_email_optout.py index 8203443341..90198e8186 100644 --- a/openedx/core/djangoapps/user_api/management/commands/bulk_user_org_email_optout.py +++ b/openedx/core/djangoapps/user_api/management/commands/bulk_user_org_email_optout.py @@ -21,6 +21,7 @@ from __future__ import absolute_import, print_function import csv import logging import time +from textwrap import dedent from django.core.management.base import BaseCommand, CommandError from django.db import connections @@ -32,8 +33,23 @@ log = logging.getLogger(__name__) class Command(BaseCommand): """ - Implementation of the bulk_user_org_email_optout command. + One-off script to opt-out users for email from orgs. + + Input: A CSV file with a user_id,org pair per line. For example: + + 1962921,FooX + 5506350,BarX + 5709986,FooX + + Lines formatted with a double-quoted org also work fine, such as: + + 5506350,"BarX" + + Opts-out every specified user/org combo row from email by setting the 'email-optin' tag to 'False'. + If the user/org combo does not currently exist in the table, a row will be created for it which + will be have the 'email-optin' tag set to 'False'. """ + help = dedent(__doc__).strip() # Default number of user/org opt-outs to perform in each DB transaction. DEFAULT_CHUNK_SIZE = 1000 diff --git a/openedx/core/djangoapps/user_api/management/commands/create_user_gdpr_testing.py b/openedx/core/djangoapps/user_api/management/commands/create_user_gdpr_testing.py index ff9f4145b3..03395cd9c4 100644 --- a/openedx/core/djangoapps/user_api/management/commands/create_user_gdpr_testing.py +++ b/openedx/core/djangoapps/user_api/management/commands/create_user_gdpr_testing.py @@ -7,6 +7,7 @@ Optionally takes in username, email, and course UUID arguments. from __future__ import absolute_import, unicode_literals from datetime import datetime +from textwrap import dedent from uuid import uuid4 from consent.models import DataSharingConsent @@ -34,8 +35,11 @@ from ...models import UserOrgTag class Command(BaseCommand): """ - Implementation of the create_user_gdpr_testing command. + Create a user with GDPR P1 PII for manual testing. + Enrolls the user in the DemoX course. + Optionally takes in username, email, and course UUID arguments. """ + help = dedent(__doc__).strip() def add_arguments(self, parser): parser.add_argument( diff --git a/openedx/core/djangoapps/user_api/management/commands/sync_hubspot_contacts.py b/openedx/core/djangoapps/user_api/management/commands/sync_hubspot_contacts.py index a838381562..91262877dd 100644 --- a/openedx/core/djangoapps/user_api/management/commands/sync_hubspot_contacts.py +++ b/openedx/core/djangoapps/user_api/management/commands/sync_hubspot_contacts.py @@ -9,6 +9,7 @@ import json import time import traceback from datetime import datetime, timedelta +from textwrap import dedent import six.moves.urllib.parse # pylint: disable=import-error from django.contrib.auth.models import User @@ -28,6 +29,7 @@ class Command(BaseCommand): Command to create contacts in hubspot for those partner who has enabled hubspot integration. This command is suppose to sync contact with hubspot on daily basis. """ + help = dedent(__doc__).strip() def _get_hubspot_enabled_sites(self): """ diff --git a/openedx/core/djangoapps/verified_track_content/management/commands/swap_from_auto_track_cohort_pilot.py b/openedx/core/djangoapps/verified_track_content/management/commands/swap_from_auto_track_cohort_pilot.py index 2596d1da75..50300c8efc 100644 --- a/openedx/core/djangoapps/verified_track_content/management/commands/swap_from_auto_track_cohort_pilot.py +++ b/openedx/core/djangoapps/verified_track_content/management/commands/swap_from_auto_track_cohort_pilot.py @@ -1,18 +1,19 @@ """Management command to migrate a course's xblock's group_access from Verified Track Cohorts to Enrollment Tracks""" from __future__ import absolute_import, print_function -from contentstore.course_group_config import GroupConfiguration +from textwrap import dedent + from django.conf import settings -from course_modes.models import CourseMode from django.core.management.base import BaseCommand, CommandError +from contentstore.course_group_config import GroupConfiguration +from course_modes.models import CourseMode from openedx.core.djangoapps.course_groups.cohorts import CourseCohort -from openedx.core.djangoapps.course_groups.models import (CourseUserGroup, CourseUserGroupPartitionGroup) +from openedx.core.djangoapps.course_groups.models import CourseUserGroup, CourseUserGroupPartitionGroup from openedx.core.djangoapps.verified_track_content.models import ( MigrateVerifiedTrackCohortsSetting, VerifiedTrackCohortedCourse ) - from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID @@ -23,6 +24,7 @@ class Command(BaseCommand): """ Migrates a course's xblock's group_access from Verified Track Cohorts to Enrollment Tracks """ + help = dedent(__doc__).strip() def handle(self, *args, **options): diff --git a/openedx/features/course_duration_limits/management/commands/cdl_setup_models_to_send_test_emails.py b/openedx/features/course_duration_limits/management/commands/cdl_setup_models_to_send_test_emails.py index 554c0187c5..f78964de5b 100644 --- a/openedx/features/course_duration_limits/management/commands/cdl_setup_models_to_send_test_emails.py +++ b/openedx/features/course_duration_limits/management/commands/cdl_setup_models_to_send_test_emails.py @@ -5,6 +5,7 @@ A managment command that can be used to set up Schedules with various configurat from __future__ import absolute_import import datetime +from textwrap import dedent import factory import pytz @@ -31,6 +32,7 @@ class Command(BaseCommand): A management command that generates schedule objects for all expected course duration limit email types, so that it is easy to generate test emails of all available types. """ + help = dedent(__doc__).strip() def handle(self, *args, **options): courses = modulestore().get_courses() @@ -52,5 +54,4 @@ class Command(BaseCommand): CourseModeFactory.create(course_id=course_overview.id, mode_slug=CourseMode.AUDIT) CourseModeFactory.create(course_id=course_overview.id, mode_slug=CourseMode.VERIFIED) CourseDurationLimitExpirySchedule.create_batch(20, enrollment__course=course_overview) - ScheduleConfigFactory.create(site=Site.objects.get(name='example.com')) diff --git a/openedx/features/course_duration_limits/management/commands/send_access_expiry_reminder.py b/openedx/features/course_duration_limits/management/commands/send_access_expiry_reminder.py index ff7014be51..354bb188fa 100644 --- a/openedx/features/course_duration_limits/management/commands/send_access_expiry_reminder.py +++ b/openedx/features/course_duration_limits/management/commands/send_access_expiry_reminder.py @@ -3,9 +3,10 @@ Send out reminder emails for any students who will lose access to course content in 7 days. """ - from __future__ import absolute_import +from textwrap import dedent + from openedx.core.djangoapps.schedules.management.commands import SendEmailBaseCommand from openedx.features.course_duration_limits.tasks import CourseDurationLimitExpiryReminder @@ -13,6 +14,13 @@ from ... import resolvers class Command(SendEmailBaseCommand): + """ + Send out reminder emails for any students who will lose access + to course content in 7 days. + + ./manage.py lms send_access_expiry_reminder + """ + help = dedent(__doc__).strip() async_send_task = CourseDurationLimitExpiryReminder log_prefix = resolvers.EXPIRY_REMINDER_LOG_PREFIX offsets = (7,) # Days until Course Duration Limit expiry