internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: uccser/cs-unplugged

Issue:
Store custom Kordac templates
The custom Kordac templates for Markdown conversion need to be stored within the repository.
Gut instinct is to store these within the `templates` directory under `markdown_templates` and then exclude this folder from the Django template loader (to avoid loading unused templates in serving webpages).

These can then be loaded for Kordac (possibly a Django loader would do the job).


Discussion:
Would have to change settings file (?) to make sure it doesn't traverse the `markdown_templates` folder.

Resolving patch:
diff --git a/csunplugged/utils/BaseLoader.py b/csunplugged/utils/BaseLoader.py
--- a/csunplugged/utils/BaseLoader.py
+++ b/csunplugged/utils/BaseLoader.py
@@ -2,6 +2,9 @@
 import mdx_math
 import abc
 import sys
+import re
+import os.path
+from os import listdir
 from kordac import Kordac
 from .check_converter_required_files import check_required_files
 
@@ -21,10 +24,7 @@ def setup_md_to_html_converter(self):
         """Create Kordac converter with custom processors, html templates,
         and extensions.
         """
-        templates = dict()
-        templates['scratch'] = '<div><object data="{% autoescape false -%}{{ "{% get_static_prefix %}" }}img/scratch-blocks-{{ hash }}.svg{%- endautoescape %}" type="image/svg+xml" /></div>'  # noqa: E501 Fixed in #77
-        templates['iframe'] = '<iframe allowtransparency="true" width="485" height="402" src="{{ link }}" frameborder="0" allowfullscreen="true"></iframe>'  # noqa: E501 Fixed in #77
-        templates['heading'] = '<{{ heading_type }} id="{{ title_slug }}">{{ title }}</{{ heading_type }}>'  # noqa: E501 Fixed in #77
+        templates = self.load_template_files()
         extensions = [
             'markdown.extensions.fenced_code',
             'markdown.extensions.codehilite',
@@ -75,6 +75,19 @@ def load_yaml_file(self, yaml_file_path):
         yaml_file = open(yaml_file_path, encoding='UTF-8').read()
         return yaml.load(yaml_file)
 
+    def load_template_files(self):
+        templates = dict()
+        template_path = os.path.join(
+            os.path.dirname(__file__),
+            'custom_converter_templates/'
+        )
+        for file in listdir(template_path):
+            template_file = re.search(r'(.*?).html$', file)
+            if template_file:
+                template_name = template_file.groups()[0]
+                templates[template_name] = open(template_path + file).read()
+        return templates
+
     @abc.abstractmethod
     def load(self):
         raise NotImplementedError('subclass does not implement this method')


Test patch:
Repository: uccser/cs-unplugged

Issue:
Check images in content are saved in static folder
Once the md input has been converted, we should check that the required images have been saved in the static/img/ folder.


Discussion:

Resolving patch:
diff --git a/csunplugged/utils/BaseLoader.py b/csunplugged/utils/BaseLoader.py
--- a/csunplugged/utils/BaseLoader.py
+++ b/csunplugged/utils/BaseLoader.py
@@ -76,6 +76,11 @@ def load_yaml_file(self, yaml_file_path):
         return yaml.load(yaml_file)
 
     def load_template_files(self):
+        """Loads custom HTMl templates for converter
+
+        Returns:
+           templates: dictionary of html templates
+        """
         templates = dict()
         template_path = os.path.join(
             os.path.dirname(__file__),
diff --git a/csunplugged/utils/MissingImageError.py b/csunplugged/utils/MissingImageError.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/utils/MissingImageError.py
@@ -0,0 +1,11 @@
+class MissingImageError(Exception):
+    """Exception raised when an expected image cannot be found
+        in static/
+        image: file path given in md text for missing image
+        message: explanation of why error was thrown
+    """
+
+    def __init__(self, image, message):
+        super().__init__(message)
+        self.image = image
+        self.message = message
diff --git a/csunplugged/utils/check_converter_required_files.py b/csunplugged/utils/check_converter_required_files.py
--- a/csunplugged/utils/check_converter_required_files.py
+++ b/csunplugged/utils/check_converter_required_files.py
@@ -1,5 +1,7 @@
 import os
 import os.path
+from django.contrib.staticfiles import finders
+from .MissingImageError import MissingImageError
 
 
 def check_required_files(required_files):
@@ -10,6 +12,7 @@ def check_required_files(required_files):
         required_files (dict): Dictionary of required files data.
     """
     render_scratch_images(required_files['scratch_images'])
+    find_image_files(required_files['images'])
 
 
 def render_scratch_images(scratch_images):
@@ -27,3 +30,17 @@ def render_scratch_images(scratch_images):
         if not os.path.isfile(filepath):
             with open(filepath, 'w') as scratch_temp_file:
                 scratch_temp_file.write(scratch_image.text)
+
+
+def find_image_files(images):
+    """Confirm each image is in static folder
+
+    Args:
+        images (set): image file names
+
+    Raises:
+        MissingImageError: when image file cannot be found
+    """
+    for image in images:
+        if not finders.find(image):
+            raise MissingImageError(image, 'Image cannot be found: {}'.format(image))


Test patch:
Repository: uccser/cs-unplugged

Issue:
Fix __str__ function in ProgrammingExerciseLanguageImplementation
The `__str__` function of `ProgrammingExerciseLanguageImplementation` returns an unknown property which creates an error.


Discussion:
Add prog. ex. lang. imp. to loader log output.

Resolving patch:
diff --git a/csunplugged/topics/management/commands/_CurriculumIntegrationsLoader.py b/csunplugged/topics/management/commands/_CurriculumIntegrationsLoader.py
--- a/csunplugged/topics/management/commands/_CurriculumIntegrationsLoader.py
+++ b/csunplugged/topics/management/commands/_CurriculumIntegrationsLoader.py
@@ -48,7 +48,6 @@ def load(self):
                     prerequisite_lessons_slugs = integration_data['prerequisite-lessons']
                     for prerequisite_lessons_slug in prerequisite_lessons_slugs:
                         (unit_plan_slug, lesson_slug) = prerequisite_lessons_slug.split('/')
-                        print(unit_plan_slug, lesson_slug)
                         lesson = Lesson.objects.get(
                             slug=lesson_slug,
                             unit_plan__slug=unit_plan_slug,
diff --git a/csunplugged/topics/management/commands/_ProgrammingExerciseLoader.py b/csunplugged/topics/management/commands/_ProgrammingExerciseLoader.py
--- a/csunplugged/topics/management/commands/_ProgrammingExerciseLoader.py
+++ b/csunplugged/topics/management/commands/_ProgrammingExerciseLoader.py
@@ -40,6 +40,9 @@ def load(self):
         )
         programming_exercise.save()
 
+        LOG_TEMPLATE = 'Added Programming Exercise: {}'
+        self.log(LOG_TEMPLATE.format(programming_exercise.name), 1)
+
         language_solutions = self.exercise_structure['programming-languages']
         for language in language_solutions:
             # This gets the language for the solution, if not found it should throw an error!
@@ -66,11 +69,11 @@ def load(self):
             )
             implementation.save()
 
+            LOG_TEMPLATE = 'Added Language Implementation: {}'
+            self.log(LOG_TEMPLATE.format(implementation.language), 2)
+
         for learning_outcome_slug in self.exercise_structure['learning-outcomes']:
             learning_outcome = LearningOutcome.objects.get(
                 slug=learning_outcome_slug
             )
             programming_exercise.learning_outcomes.add(learning_outcome)
-
-        LOG_TEMPLATE = 'Added Programming Exercise: {}'
-        self.log(LOG_TEMPLATE.format(programming_exercise.name), 1)
diff --git a/csunplugged/topics/models.py b/csunplugged/topics/models.py
--- a/csunplugged/topics/models.py
+++ b/csunplugged/topics/models.py
@@ -144,7 +144,12 @@ class ProgrammingExerciseLanguageImplementation(models.Model):
     solution = models.TextField()
 
     def __str__(self):
-        return self.name
+        return '{} for exercise {}.{}, {}'.format(
+            self.language.name,
+            self.exercise.exercise_set_number,
+            self.exercise.exercise_number,
+            self.exercise.name
+        )
 
 
 class Lesson(models.Model):


Test patch:
Repository: uccser/cs-unplugged

Issue:
Invalid filename for blank resources
When downloading a resource that is blank, the filename is `Sorting Network (0 to -1).pdf`.

The filename should be something like `Sorting Network (blank).pdf`.



Discussion:

Resolving patch:
diff --git a/csunplugged/resources/views/sorting_network.py b/csunplugged/resources/views/sorting_network.py
--- a/csunplugged/resources/views/sorting_network.py
+++ b/csunplugged/resources/views/sorting_network.py
@@ -45,9 +45,12 @@ def subtitle(get_request, resource):
     Used after the resource name in the filename, and
     also on the resource image.
     """
-    SUBTITLE_TEMPLATE = '{} to {}'
-    range_min, range_max, font_size = number_range(get_request)
-    text = SUBTITLE_TEMPLATE.format(range_min, range_max - 1)
+    if get_request['prefilled_values'] == 'blank':
+        text = 'blank'
+    else:
+        SUBTITLE_TEMPLATE = '{} to {}'
+        range_min, range_max, font_size = number_range(get_request)
+        text = SUBTITLE_TEMPLATE.format(range_min, range_max - 1)
     return text
 
 
diff --git a/csunplugged/resources/views/treasure_hunt.py b/csunplugged/resources/views/treasure_hunt.py
--- a/csunplugged/resources/views/treasure_hunt.py
+++ b/csunplugged/resources/views/treasure_hunt.py
@@ -13,10 +13,9 @@ def resource_image(get_request, resource):
     image = Image.open(image_path)
     draw = ImageDraw.Draw(image)
 
-    (range_min, range_max, font_size) = number_range(get_request)
-
     # Add numbers to image if required
     if get_request['prefilled_values'] != 'blank':
+        (range_min, range_max, font_size) = number_range(get_request)
         font = ImageFont.truetype(font_path, font_size)
 
         total_numbers = 26
@@ -66,10 +65,13 @@ def subtitle(get_request, resource):
     Used after the resource name in the filename, and
     also on the resource image.
     """
-    SUBTITLE_TEMPLATE = '{} - {} to {}'
-    number_order_text = get_request['number_order'].title()
-    range_min, range_max, font_size = number_range(get_request)
-    text = SUBTITLE_TEMPLATE.format(number_order_text, range_min, range_max - 1)
+    if get_request['prefilled_values'] == 'blank':
+        text = 'blank'
+    else:
+        SUBTITLE_TEMPLATE = '{} - {} to {}'
+        number_order_text = get_request['number_order'].title()
+        range_min, range_max, font_size = number_range(get_request)
+        text = SUBTITLE_TEMPLATE.format(number_order_text, range_min, range_max - 1)
     return text
 
 


Test patch:
Repository: uccser/cs-unplugged

Issue:
Remove topic query from homepage
When the homepage is loaded, a database query is performed. This is currently not needed and should be removed.
Remove topic query from homepage
When the homepage is loaded, a database query is performed. This is currently not needed and should be removed.


Discussion:

Resolving patch:
diff --git a/csunplugged/general/views.py b/csunplugged/general/views.py
--- a/csunplugged/general/views.py
+++ b/csunplugged/general/views.py
@@ -4,14 +4,6 @@
 class GeneralIndexView(TemplateView):
     template_name = 'general/index.html'
 
-    def get_context_data(self, **kwargs):
-        # TODO: Investigate if importing model from another
-        # app is sensible/best approach.
-        from topics.models import Topic
-        context = super(GeneralIndexView, self).get_context_data(**kwargs)
-        context['total_topics'] = Topic.objects.count()
-        return context
-
 
 class GeneralAboutView(TemplateView):
     template_name = 'general/about.html'


Test patch:
Repository: uccser/cs-unplugged

Issue:
Add 'About' page content
Using content from existing website.


Discussion:

Resolving patch:
diff --git a/csunplugged/general/urls.py b/csunplugged/general/urls.py
--- a/csunplugged/general/urls.py
+++ b/csunplugged/general/urls.py
@@ -6,5 +6,8 @@
 
 urlpatterns = [
     url(r'^about/$', views.GeneralAboutView.as_view(), name='about'),
+    url(r'^contact/$', views.GeneralContactView.as_view(), name='contact'),
+    url(r'^people/$', views.GeneralPeopleView.as_view(), name='people'),
+    url(r'^principles/$', views.GeneralPrinciplesView.as_view(), name='principles'),
     url(r'^$', views.GeneralIndexView.as_view(), name='home'),
 ]
diff --git a/csunplugged/general/views.py b/csunplugged/general/views.py
--- a/csunplugged/general/views.py
+++ b/csunplugged/general/views.py
@@ -16,6 +16,24 @@ class GeneralAboutView(TemplateView):
     template_name = 'general/about.html'
 
 
+class GeneralContactView(TemplateView):
+    """View for the contact page that renders from a template."""
+
+    template_name = 'general/contact.html'
+
+
+class GeneralPeopleView(TemplateView):
+    """View for the people page that renders from a template."""
+
+    template_name = 'general/people.html'
+
+
+class GeneralPrinciplesView(TemplateView):
+    """View for the princples page that renders from a template."""
+
+    template_name = 'general/principles.html'
+
+
 def health_check(request):
     """Return heath check response for Google App Engine.
 


Test patch:
Repository: uccser/cs-unplugged

Issue:
Add Binary plugged in exercises
## Description

Clearly and concisely describe the issue or suggestion here:


Add Binary plugged in exercises from google doc (private file)




### Checklist

*Change the space in the box to an `x` for those you have completed. You can also fill these out after creating the issue.*

- [ ] I have linked any relevant existing issues/suggestions in the description above (include `#???` in your description to reference an issue, where `???` is the issue number).




Discussion:

Resolving patch:
diff --git a/csunplugged/topics/management/commands/_ProgrammingExercisesLoader.py b/csunplugged/topics/management/commands/_ProgrammingExercisesLoader.py
--- a/csunplugged/topics/management/commands/_ProgrammingExercisesLoader.py
+++ b/csunplugged/topics/management/commands/_ProgrammingExercisesLoader.py
@@ -93,9 +93,9 @@ def load(self):
                 name=exercise_content.title,
                 exercise_set_number=exercise_set_number,
                 exercise_number=exercise_number,
-                content=exercise_content.html_string
+                content=exercise_content.html_string,
+                difficulty=difficulty_level
             )
-            programming_exercise.difficulty.add(difficulty_level)
             programming_exercise.save()
 
             LOG_TEMPLATE = "Added Programming Exercise: {}"
diff --git a/csunplugged/topics/migrations/0045_auto_20170502_2111.py b/csunplugged/topics/migrations/0045_auto_20170502_2111.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/topics/migrations/0045_auto_20170502_2111.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11 on 2017-05-02 21:11
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('topics', '0044_merge_20170423_2100'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='programmingexercise',
+            name='difficulty',
+        ),
+        migrations.AddField(
+            model_name='programmingexercise',
+            name='difficulty',
+            field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='difficulty_programming_exercises', to='topics.ProgrammingExerciseDifficulty'),
+            preserve_default=False,
+        ),
+    ]
diff --git a/csunplugged/topics/models.py b/csunplugged/topics/models.py
--- a/csunplugged/topics/models.py
+++ b/csunplugged/topics/models.py
@@ -140,8 +140,9 @@ class ProgrammingExercise(models.Model):
         LearningOutcome,
         related_name='programming_exercise_learning_outcomes'
     )
-    difficulty = models.ManyToManyField(
+    difficulty = models.ForeignKey(
         ProgrammingExerciseDifficulty,
+        on_delete=models.CASCADE,
         related_name='difficulty_programming_exercises'
     )
 


Test patch:
Repository: uccser/cs-unplugged

Issue:
Django Debug Toolbar doesn't display in local Docker development environment
Created from work in #193.


Discussion:

Resolving patch:
diff --git a/csunplugged/config/settings/local.py b/csunplugged/config/settings/local.py
--- a/csunplugged/config/settings/local.py
+++ b/csunplugged/config/settings/local.py
@@ -9,8 +9,6 @@
 - Use console backend for emails
 """
 
-import socket
-import os
 from .base import *  # noqa: F403
 
 # DATABASE CONFIGURATION
@@ -56,16 +54,23 @@
 INSTALLED_APPS += ['debug_toolbar', ]  # noqa: F405
 
 INTERNAL_IPS = ['127.0.0.1', '10.0.2.2', ]
-# tricks to have debug toolbar when developing with docker
-if os.environ.get('USE_DOCKER') == 'yes':
-    ip = socket.gethostbyname(socket.gethostname())
-    INTERNAL_IPS += [ip[:-1] + '1']
+
+
+def show_django_debug_toolbar(request):
+    """Show Django Debug Toolbar in every request when running locally.
+
+    Args:
+        request: The request object.
+    """
+    return True
+
 
 DEBUG_TOOLBAR_CONFIG = {
     'DISABLE_PANELS': [
         'debug_toolbar.panels.redirects.RedirectsPanel',
     ],
     'SHOW_TEMPLATE_CONTEXT': True,
+    "SHOW_TOOLBAR_CALLBACK": show_django_debug_toolbar,
 }
 
 # django-extensions
@@ -79,4 +84,4 @@
 
 # Your local stuff: Below this line define 3rd party library settings
 # ----------------------------------------------------------------------------
-LOCAL_APPS + ['dev.apps.DevConfig']  # noqa: F405
+INSTALLED_APPS += ['dev.apps.DevConfig']  # noqa: F405


Test patch:
diff --git a/csunplugged/config/settings/testing.py b/csunplugged/config/settings/testing.py
--- a/csunplugged/config/settings/testing.py
+++ b/csunplugged/config/settings/testing.py
@@ -4,6 +4,14 @@
 from .base import *  # noqa: F403
 
 
+# DATABASE CONFIGURATION
+# ----------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
+DATABASES = {
+    'default': env.db('DATABASE_URL'),  # noqa: F405
+}
+DATABASES['default']['ATOMIC_REQUESTS'] = True
+
 # DEBUG
 # ----------------------------------------------------------------------------
 # Turn debug off so tests run faster
@@ -14,7 +22,7 @@
 # ----------------------------------------------------------------------------
 # See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
 # Note: This key only used for development and testing.
-SECRET_KEY = env('DJANGO_SECRET_KEY', default='CHANGEME!!!')  # noqa: F405
+SECRET_KEY = env('DJANGO_SECRET_KEY', default='l@@)w&&%&u37+sjz^lsx^+29y_333oid3ygxzucar^8o(axo*f')  # noqa: F405
 
 # Mail settings
 # ----------------------------------------------------------------------------
@@ -56,3 +64,7 @@
         'django.template.loaders.app_directories.Loader',
     ], ],
 ]
+
+# Your local stuff: Below this line define 3rd party library settings
+# ----------------------------------------------------------------------------
+INSTALLED_APPS += ['dev.apps.DevConfig']  # noqa: F405
Repository: uccser/cs-unplugged

Issue:
Automate deployment to development servers
To investigate:

- [x] ~Setting `gsutil` to do complete sync.~ Will not use for the moment, see: https://cloud.google.com/storage/docs/gsutil/commands/rsync#be-careful-when-using--d-option
- [x] Using script to set environment variables for the specific deployment.
- [x] Check for secrets within logs.
- [x] Use new database account credentials.
  - [x] Delete old credentials once deployed.
- [x] Set `.travis.yml` to deploy on `develop`.
- [x] Update documentation.
Automate deployment to development servers
To investigate:

- [x] ~Setting `gsutil` to do complete sync.~ Will not use for the moment, see: https://cloud.google.com/storage/docs/gsutil/commands/rsync#be-careful-when-using--d-option
- [x] Using script to set environment variables for the specific deployment.
- [x] Check for secrets within logs.
- [x] Use new database account credentials.
  - [x] Delete old credentials once deployed.
- [x] Set `.travis.yml` to deploy on `develop`.
- [x] Update documentation.


Discussion:

Resolving patch:
diff --git a/csunplugged/config/settings/database_proxy.py b/csunplugged/config/settings/database_proxy.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/config/settings/database_proxy.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+"""Django settings for connecting via Google Cloud SQL Proxy."""
+
+from .base import *  # noqa: F403
+
+
+# DATABASE CONFIGURATION
+# ----------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
+DATABASES = {
+    "default": {
+        "ENGINE": "django.db.backends.postgresql",
+        "HOST": "127.0.0.1",
+        "PORT": "5433",
+        "NAME": "csunplugged",
+        "USER": env("GOOGLE_CLOUD_SQL_DATABASE_USERNAME"),  # noqa: F405
+        "PASSWORD": env("GOOGLE_CLOUD_SQL_DATABASE_PASSWORD"),  # noqa: F405
+        "ATOMIC_REQUESTS": True,
+    }
+}
+
+SECRET_KEY = env("DJANGO_SECRET_KEY")  # noqa: F405


Test patch:
diff --git a/docs/source/developer/test_suite.rst b/docs/source/developer/test_suite.rst
--- a/docs/source/developer/test_suite.rst
+++ b/docs/source/developer/test_suite.rst
@@ -1,4 +1,4 @@
-The Test Suite
+Test Suite
 ##############################################################################
 
 .. contents:: Contents
@@ -33,4 +33,3 @@ Structure
       │   ├── test_urls.py
       │   └── test_views.py
       └── BaseTest.py
-