'Fix a StudentModule with a trailing newline in the course_id.
Returns a count of (row modified, )
At the end of this method call, the record should no longer have a
trailing newline for the course_id. There are three possible outcomes:
1. There was never a conflicting entry:
-> We just update this row.
2. Conflict and the other row (with correct course_id) wins:
-> We archive this row.
2. Conflict and this row wins:
-> We copy the data to the conflicting row (the one that has a
correct course_id), and archive this row.
Even though all the StudentModule entries coming in here have trailing
newlines in the course_id, the deserialization logic will obscure that
(it gets parsed out when read from the database). We will also
automatically strip the newlines when writing back to the database, so
we have to be very careful about violating unique constraints by doing
unintended updates. That\'s why we only do an update to
newline_course_row if no correct_course_row exists.'

def fix_row(self, read_only_newline_course_row, dry_run=False):

    log.info('Fixing    row    %s,    course    %s,    student    %s,    block    %s', read_only_newline_course_row.id, read_only_newline_course_row.course_id, read_only_newline_course_row.student_id, read_only_newline_course_row.module_state_key)
    try:
        newline_course_row = StudentModule.objects.get(id=read_only_newline_course_row.id)
    except StudentModule.DoesNotExist:
        log.exception('Could    not    find    editable    CSM    row    %s', read_only_newline_course_row.id)
        return FixResult(record_trimmed=0, data_copied=0, record_archived=0, capa_merge=0, error=1)
    try:
        correct_course_row = StudentModule.objects.get(student_id=newline_course_row.student_id, course_id=newline_course_row.course_id, module_state_key=newline_course_row.module_state_key)
        assert (correct_course_row.pk != newline_course_row.pk)
    except StudentModule.DoesNotExist:
        correct_course_row = None
    if (correct_course_row is None):
        log.info('No    conflict:    Removing    trailing    newline    from    course_id    in    CSM    row    %s    -    (%s)    %s', newline_course_row.id, newline_course_row.module_type, newline_course_row.module_state_key)
        if dry_run:
            return FixResult(record_trimmed=1, data_copied=0, record_archived=0, capa_merge=0, error=0)
        try:
            with transaction.atomic():
                newline_course_row.save()
            return FixResult(record_trimmed=1, data_copied=0, record_archived=0, capa_merge=0, error=0)
        except DatabaseError:
            log.exception('Could    not    remove    newline    and    update    CSM    row    %s', newline_course_row.id)
            return FixResult(record_trimmed=0, data_copied=0, record_archived=0, capa_merge=0, error=1)
    if (newline_course_row.module_type == 'problem'):
        return self.handle_capa_merge(correct_course_row, newline_course_row, dry_run)
    row_to_keep = self.row_to_keep(correct_course_row, newline_course_row)
    if (row_to_keep.id == newline_course_row.id):
        log.info('Conflict:    Choosing    data    from    newline    course,    copying    data    from    CSM    %s    to    %s    -    (%s)    %s', newline_course_row.id, correct_course_row.id, newline_course_row.module_type, newline_course_row.module_state_key)
        correct_course_row.state = newline_course_row.state
        correct_course_row.grade = newline_course_row.grade
        correct_course_row.max_grade = newline_course_row.max_grade
        if dry_run:
            return FixResult(record_trimmed=0, data_copied=1, record_archived=1, capa_merge=0, error=0)
        try:
            with transaction.atomic():
                correct_course_row.save()
                self.cleanup_row(newline_course_row)
            return FixResult(record_trimmed=0, data_copied=1, record_archived=1, capa_merge=0, error=0)
        except DatabaseError:
            log.exception('Failed    while    trying    save    CSM    row    %s    and    archiving    row    %s', correct_course_row.id, newline_course_row.id)
            return FixResult(record_trimmed=0, data_copied=0, record_archived=0, capa_merge=0, error=1)
    log.info('Conflict:    Choosing    data    from    record    with    correct    course_id    (%s)    and    archiving    row    with    newline    in    course_id    (%s)    -    (%s)    %s', correct_course_row.id, newline_course_row.id, newline_course_row.module_type, newline_course_row.module_state_key)
    if dry_run:
        return FixResult(record_trimmed=0, data_copied=0, record_archived=1, capa_merge=0, error=0)
    try:
        with transaction.atomic():
            self.cleanup_row(newline_course_row)
        return FixResult(record_trimmed=0, data_copied=0, record_archived=1, capa_merge=0, error=0)
    except DatabaseError:
        log.exception('Could    not    archive    CSM    row    %s', newline_course_row.id)
        return FixResult(record_trimmed=0, data_copied=0, record_archived=0, capa_merge=0, error=1)
