From 84a96e40c4abf3ae70f6a3202800ce403a53d166 Mon Sep 17 00:00:00 2001
From: Sarina Canelake <sarina@edx.org>
Date: Sun, 6 Dec 2015 11:38:05 -0500
Subject: [PATCH] Remove 'Fold It' XModule

---
 common/lib/xmodule/setup.py                   |   1 -
 .../xmodule/css/foldit/leaderboard.scss       |  20 -
 common/lib/xmodule/xmodule/foldit_module.py   | 206 ---------
 common/test/db_cache/bok_choy_schema.sql      |  39 --
 lms/djangoapps/courseware/grades.py           |   5 +-
 lms/djangoapps/foldit/__init__.py             |   0
 .../foldit/migrations/0001_initial.py         |  47 --
 lms/djangoapps/foldit/migrations/__init__.py  |   0
 lms/djangoapps/foldit/models.py               | 142 ------
 lms/djangoapps/foldit/tests.py                | 403 ------------------
 lms/djangoapps/foldit/views.py                | 175 --------
 lms/envs/common.py                            |   3 -
 .../sass/course/courseware/_courseware.scss   |  14 -
 lms/templates/foldit.html                     |  12 -
 lms/templates/folditbasic.html                |  33 --
 lms/templates/folditchallenge.html            |  18 -
 lms/urls.py                                   |   6 -
 17 files changed, 2 insertions(+), 1122 deletions(-)
 delete mode 100644 common/lib/xmodule/xmodule/css/foldit/leaderboard.scss
 delete mode 100644 common/lib/xmodule/xmodule/foldit_module.py
 delete mode 100644 lms/djangoapps/foldit/__init__.py
 delete mode 100644 lms/djangoapps/foldit/migrations/0001_initial.py
 delete mode 100644 lms/djangoapps/foldit/migrations/__init__.py
 delete mode 100644 lms/djangoapps/foldit/models.py
 delete mode 100644 lms/djangoapps/foldit/tests.py
 delete mode 100644 lms/djangoapps/foldit/views.py
 delete mode 100644 lms/templates/foldit.html
 delete mode 100644 lms/templates/folditbasic.html
 delete mode 100644 lms/templates/folditchallenge.html

diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py
index e1e50daf981..5b6b0b58f5a 100644
--- a/common/lib/xmodule/setup.py
+++ b/common/lib/xmodule/setup.py
@@ -36,7 +36,6 @@ XMODULES = [
     "textannotation = xmodule.textannotation_module:TextAnnotationDescriptor",
     "videoannotation = xmodule.videoannotation_module:VideoAnnotationDescriptor",
     "imageannotation = xmodule.imageannotation_module:ImageAnnotationDescriptor",
-    "foldit = xmodule.foldit_module:FolditDescriptor",
     "word_cloud = xmodule.word_cloud_module:WordCloudDescriptor",
     "hidden = xmodule.hidden_module:HiddenDescriptor",
     "raw = xmodule.raw_module:RawDescriptor",
diff --git a/common/lib/xmodule/xmodule/css/foldit/leaderboard.scss b/common/lib/xmodule/xmodule/css/foldit/leaderboard.scss
deleted file mode 100644
index 3173ffbcdcc..00000000000
--- a/common/lib/xmodule/xmodule/css/foldit/leaderboard.scss
+++ /dev/null
@@ -1,20 +0,0 @@
-$leaderboard: #F4F4F4;
-
-section.foldit {
-    div.folditchallenge {
-        table {
-            border: 1px solid lighten($leaderboard, 10%);
-            border-collapse: collapse;
-            margin-top: $baseline;
-        }
-        th {
-            background: $leaderboard;
-            color: darken($leaderboard, 25%);
-        }
-        td {
-            background: lighten($leaderboard, 3%);
-            border-bottom: 1px solid $white;
-            padding: 8px;
-        }
-    }
-}
diff --git a/common/lib/xmodule/xmodule/foldit_module.py b/common/lib/xmodule/xmodule/foldit_module.py
deleted file mode 100644
index 67f3c93791e..00000000000
--- a/common/lib/xmodule/xmodule/foldit_module.py
+++ /dev/null
@@ -1,206 +0,0 @@
-import logging
-from lxml import etree
-
-from pkg_resources import resource_string
-
-from xmodule.editing_module import EditingDescriptor
-from xmodule.x_module import XModule
-from xmodule.xml_module import XmlDescriptor
-from xblock.fields import Scope, Integer, String
-from .fields import Date
-
-
-log = logging.getLogger(__name__)
-
-
-class FolditFields(object):
-    # default to what Spring_7012x uses
-    required_level_half_credit = Integer(default=3, scope=Scope.settings)
-    required_sublevel_half_credit = Integer(default=5, scope=Scope.settings)
-    required_level = Integer(default=4, scope=Scope.settings)
-    required_sublevel = Integer(default=5, scope=Scope.settings)
-    due = Date(help="Date that this problem is due by", scope=Scope.settings)
-
-    show_basic_score = String(scope=Scope.settings, default='false')
-    show_leaderboard = String(scope=Scope.settings, default='false')
-
-
-class FolditModule(FolditFields, XModule):
-
-    css = {'scss': [resource_string(__name__, 'css/foldit/leaderboard.scss')]}
-
-    def __init__(self, *args, **kwargs):
-        """
-        Example:
-         <foldit show_basic_score="true"
-            required_level="4"
-            required_sublevel="3"
-            required_level_half_credit="2"
-            required_sublevel_half_credit="3"
-            show_leaderboard="false"/>
-        """
-        super(FolditModule, self).__init__(*args, **kwargs)
-        self.due_time = self.due
-
-    def is_complete(self):
-        """
-        Did the user get to the required level before the due date?
-        """
-        # We normally don't want django dependencies in xmodule.  foldit is
-        # special.  Import this late to avoid errors with things not yet being
-        # initialized.
-        from foldit.models import PuzzleComplete
-
-        complete = PuzzleComplete.is_level_complete(
-            self.system.anonymous_student_id,
-            self.required_level,
-            self.required_sublevel,
-            self.due_time)
-        return complete
-
-    def is_half_complete(self):
-        """
-        Did the user reach the required level for half credit?
-
-        Ideally this would be more flexible than just 0, 0.5, or 1 credit. On
-        the other hand, the xml attributes for specifying more specific
-        cut-offs and partial grades can get more confusing.
-        """
-        from foldit.models import PuzzleComplete
-        complete = PuzzleComplete.is_level_complete(
-            self.system.anonymous_student_id,
-            self.required_level_half_credit,
-            self.required_sublevel_half_credit,
-            self.due_time)
-        return complete
-
-    def completed_puzzles(self):
-        """
-        Return a list of puzzles that this user has completed, as an array of
-        dicts:
-
-        [ {'set': int,
-           'subset': int,
-           'created': datetime} ]
-
-        The list is sorted by set, then subset
-        """
-        from foldit.models import PuzzleComplete
-
-        return sorted(
-            PuzzleComplete.completed_puzzles(self.system.anonymous_student_id),
-            key=lambda d: (d['set'], d['subset']))
-
-    def puzzle_leaders(self, n=10, courses=None):
-        """
-        Returns a list of n pairs (user, score) corresponding to the top
-        scores; the pairs are in descending order of score.
-        """
-        from foldit.models import Score
-
-        if courses is None:
-            courses = [self.location.course_key]
-
-        leaders = [(leader['username'], leader['score']) for leader in Score.get_tops_n(10, course_list=courses)]
-        leaders.sort(key=lambda x: -x[1])
-
-        return leaders
-
-    def get_html(self):
-        """
-        Render the html for the module.
-        """
-        goal_level = '{0}-{1}'.format(
-            self.required_level,
-            self.required_sublevel)
-
-        showbasic = (self.show_basic_score.lower() == "true")
-        showleader = (self.show_leaderboard.lower() == "true")
-
-        context = {
-            'due': self.due,
-            'success': self.is_complete(),
-            'goal_level': goal_level,
-            'completed': self.completed_puzzles(),
-            'top_scores': self.puzzle_leaders(),
-            'show_basic': showbasic,
-            'show_leader': showleader,
-            'folditbasic': self.get_basicpuzzles_html(),
-            'folditchallenge': self.get_challenge_html()
-        }
-
-        return self.system.render_template('foldit.html', context)
-
-    def get_basicpuzzles_html(self):
-        """
-        Render html for the basic puzzle section.
-        """
-        goal_level = '{0}-{1}'.format(
-            self.required_level,
-            self.required_sublevel)
-
-        context = {
-            'due': self.due,
-            'success': self.is_complete(),
-            'goal_level': goal_level,
-            'completed': self.completed_puzzles(),
-        }
-        return self.system.render_template('folditbasic.html', context)
-
-    def get_challenge_html(self):
-        """
-        Render html for challenge (i.e., the leaderboard)
-        """
-
-        context = {
-            'top_scores': self.puzzle_leaders()}
-
-        return self.system.render_template('folditchallenge.html', context)
-
-    def get_score(self):
-        """
-        0 if required_level_half_credit - required_sublevel_half_credit not
-        reached.
-        0.5 if required_level_half_credit and required_sublevel_half_credit
-        reached.
-        1 if requred_level and required_sublevel reached.
-        """
-        if self.is_complete():
-            score = 1
-        elif self.is_half_complete():
-            score = 0.5
-        else:
-            score = 0
-        return {'score': score,
-                'total': self.max_score()}
-
-    def max_score(self):
-        return 1
-
-
-class FolditDescriptor(FolditFields, XmlDescriptor, EditingDescriptor):
-    """
-    Module for adding Foldit problems to courses
-    """
-    mako_template = "widgets/html-edit.html"
-    module_class = FolditModule
-    filename_extension = "xml"
-
-    has_score = True
-
-    show_in_read_only_mode = True
-
-    js = {'coffee': [resource_string(__name__, 'js/src/html/edit.coffee')]}
-    js_module_name = "HTMLEditingDescriptor"
-
-    # The grade changes without any student interaction with the edx website,
-    # so always need to actually check.
-    always_recalculate_grades = True
-
-    @classmethod
-    def definition_from_xml(cls, xml_object, system):
-        return {}, []
-
-    def definition_to_xml(self, resource_fs):
-        xml_object = etree.Element('foldit')
-        return xml_object
diff --git a/common/test/db_cache/bok_choy_schema.sql b/common/test/db_cache/bok_choy_schema.sql
index 9856d86aa3e..a580794e373 100644
--- a/common/test/db_cache/bok_choy_schema.sql
+++ b/common/test/db_cache/bok_choy_schema.sql
@@ -1810,45 +1810,6 @@ CREATE TABLE `external_auth_externalauthmap` (
   CONSTRAINT `external_auth_externala_user_id_644e7779f2d52b9a_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 /*!40101 SET character_set_client = @saved_cs_client */;
-DROP TABLE IF EXISTS `foldit_puzzlecomplete`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `foldit_puzzlecomplete` (
-  `id` int(11) NOT NULL AUTO_INCREMENT,
-  `unique_user_id` varchar(50) NOT NULL,
-  `puzzle_id` int(11) NOT NULL,
-  `puzzle_set` int(11) NOT NULL,
-  `puzzle_subset` int(11) NOT NULL,
-  `created` datetime(6) NOT NULL,
-  `user_id` int(11) NOT NULL,
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `foldit_puzzlecomplete_user_id_4c63656af6674331_uniq` (`user_id`,`puzzle_id`,`puzzle_set`,`puzzle_subset`),
-  KEY `foldit_puzzlecomplete_ff2b2d15` (`unique_user_id`),
-  KEY `foldit_puzzlecomplete_56c088b4` (`puzzle_set`),
-  KEY `foldit_puzzlecomplete_2dc27ffb` (`puzzle_subset`),
-  CONSTRAINT `foldit_puzzlecomplete_user_id_cd0294fb3a392_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-DROP TABLE IF EXISTS `foldit_score`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `foldit_score` (
-  `id` int(11) NOT NULL AUTO_INCREMENT,
-  `unique_user_id` varchar(50) NOT NULL,
-  `puzzle_id` int(11) NOT NULL,
-  `best_score` double NOT NULL,
-  `current_score` double NOT NULL,
-  `score_version` int(11) NOT NULL,
-  `created` datetime(6) NOT NULL,
-  `user_id` int(11) NOT NULL,
-  PRIMARY KEY (`id`),
-  KEY `foldit_score_user_id_6ac502fe1f6861b2_fk_auth_user_id` (`user_id`),
-  KEY `foldit_score_ff2b2d15` (`unique_user_id`),
-  KEY `foldit_score_44726e86` (`best_score`),
-  KEY `foldit_score_32d6f808` (`current_score`),
-  CONSTRAINT `foldit_score_user_id_6ac502fe1f6861b2_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
 DROP TABLE IF EXISTS `instructor_task_instructortask`;
 /*!40101 SET @saved_cs_client     = @@character_set_client */;
 /*!40101 SET character_set_client = utf8 */;
diff --git a/lms/djangoapps/courseware/grades.py b/lms/djangoapps/courseware/grades.py
index 06a5fff5c9f..1becdeb04b0 100644
--- a/lms/djangoapps/courseware/grades.py
+++ b/lms/djangoapps/courseware/grades.py
@@ -378,8 +378,7 @@ def _grade(student, request, course, keep_raw_scores, field_data_cache, scores_c
 
             with outer_atomic():
                 # some problems have state that is updated independently of interaction
-                # with the LMS, so they need to always be scored. (E.g. foldit.,
-                # combinedopenended)
+                # with the LMS, so they need to always be scored. (E.g. combinedopenended ORA1)
                 # TODO This block is causing extra savepoints to be fired that are empty because no queries are executed
                 # during the loop. When refactoring this code please keep this outer_atomic call in mind and ensure we
                 # are not making unnecessary database queries.
@@ -699,7 +698,7 @@ def get_score(user, problem_descriptor, module_creator, scores_client, submissio
         return submissions_scores_cache[location_url]
 
     # some problems have state that is updated independently of interaction
-    # with the LMS, so they need to always be scored. (E.g. foldit.)
+    # with the LMS, so they need to always be scored. (E.g. combinedopenended ORA1.)
     if problem_descriptor.always_recalculate_grades:
         problem = module_creator(problem_descriptor)
         if problem is None:
diff --git a/lms/djangoapps/foldit/__init__.py b/lms/djangoapps/foldit/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/lms/djangoapps/foldit/migrations/0001_initial.py b/lms/djangoapps/foldit/migrations/0001_initial.py
deleted file mode 100644
index e73af4e0395..00000000000
--- a/lms/djangoapps/foldit/migrations/0001_initial.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-from django.conf import settings
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='PuzzleComplete',
-            fields=[
-                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
-                ('unique_user_id', models.CharField(max_length=50, db_index=True)),
-                ('puzzle_id', models.IntegerField()),
-                ('puzzle_set', models.IntegerField(db_index=True)),
-                ('puzzle_subset', models.IntegerField(db_index=True)),
-                ('created', models.DateTimeField(auto_now_add=True)),
-                ('user', models.ForeignKey(related_name='foldit_puzzles_complete', to=settings.AUTH_USER_MODEL)),
-            ],
-            options={
-                'ordering': ['puzzle_id'],
-            },
-        ),
-        migrations.CreateModel(
-            name='Score',
-            fields=[
-                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
-                ('unique_user_id', models.CharField(max_length=50, db_index=True)),
-                ('puzzle_id', models.IntegerField()),
-                ('best_score', models.FloatField(db_index=True)),
-                ('current_score', models.FloatField(db_index=True)),
-                ('score_version', models.IntegerField()),
-                ('created', models.DateTimeField(auto_now_add=True)),
-                ('user', models.ForeignKey(related_name='foldit_scores', to=settings.AUTH_USER_MODEL)),
-            ],
-        ),
-        migrations.AlterUniqueTogether(
-            name='puzzlecomplete',
-            unique_together=set([('user', 'puzzle_id', 'puzzle_set', 'puzzle_subset')]),
-        ),
-    ]
diff --git a/lms/djangoapps/foldit/migrations/__init__.py b/lms/djangoapps/foldit/migrations/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/lms/djangoapps/foldit/models.py b/lms/djangoapps/foldit/models.py
deleted file mode 100644
index 763f3951c4a..00000000000
--- a/lms/djangoapps/foldit/models.py
+++ /dev/null
@@ -1,142 +0,0 @@
-import logging
-
-from django.contrib.auth.models import User
-from django.db import models
-
-
-log = logging.getLogger(__name__)
-
-
-class Score(models.Model):
-    """
-    This model stores the scores of different users on FoldIt problems.
-    """
-    user = models.ForeignKey(User, db_index=True,
-                             related_name='foldit_scores')
-
-    # The XModule that wants to access this doesn't have access to the real
-    # userid.  Save the anonymized version so we can look up by that.
-    unique_user_id = models.CharField(max_length=50, db_index=True)
-    puzzle_id = models.IntegerField()
-    best_score = models.FloatField(db_index=True)
-    current_score = models.FloatField(db_index=True)
-    score_version = models.IntegerField()
-    created = models.DateTimeField(auto_now_add=True)
-
-    @staticmethod
-    def display_score(score, sum_of=1):
-        """
-        Argument:
-            score (float), as stored in the DB (i.e., "rosetta score")
-            sum_of (int): if this score is the sum of scores of individual
-               problems, how many elements are in that sum
-
-        Returns:
-            score (float), as displayed to the user in the game and in the leaderboard
-        """
-        return (-score) * 10 + 8000 * sum_of
-
-    @staticmethod
-    def get_tops_n(n, puzzles=['994559'], course_list=None):
-        """
-        Arguments:
-            puzzles: a list of puzzle ids that we will use. If not specified,
-            defaults to puzzle used in 7012x.
-            n (int): number of top scores to return
-
-
-        Returns:
-            The top n sum of scores for puzzles in <puzzles>,
-            filtered by course. If no courses is specified we default
-            the pool of students to all courses. Output is a list
-            of dictionaries, sorted by display_score:
-                [ {username: 'a_user',
-                   score: 12000} ...]
-        """
-
-        if not isinstance(puzzles, list):
-            puzzles = [puzzles]
-        if course_list is None:
-            scores = Score.objects \
-                .filter(puzzle_id__in=puzzles) \
-                .annotate(total_score=models.Sum('best_score')) \
-                .order_by('total_score')[:n]
-        else:
-            scores = Score.objects \
-                .filter(puzzle_id__in=puzzles) \
-                .filter(user__courseenrollment__course_id__in=course_list) \
-                .annotate(total_score=models.Sum('best_score')) \
-                .order_by('total_score')[:n]
-        num = len(puzzles)
-
-        return [
-            {'username': score.user.username,
-             'score': Score.display_score(score.total_score, num)}
-            for score in scores
-        ]
-
-
-class PuzzleComplete(models.Model):
-    """
-    This keeps track of the sets of puzzles completed by each user.
-
-    e.g. PuzzleID 1234, set 1, subset 3.  (Sets and subsets correspond to levels
-    in the intro puzzles)
-    """
-    class Meta(object):
-        # there should only be one puzzle complete entry for any particular
-        # puzzle for any user
-        unique_together = ('user', 'puzzle_id', 'puzzle_set', 'puzzle_subset')
-        ordering = ['puzzle_id']
-
-    user = models.ForeignKey(User, db_index=True,
-                             related_name='foldit_puzzles_complete')
-
-    # The XModule that wants to access this doesn't have access to the real
-    # userid.  Save the anonymized version so we can look up by that.
-    unique_user_id = models.CharField(max_length=50, db_index=True)
-    puzzle_id = models.IntegerField()
-    puzzle_set = models.IntegerField(db_index=True)
-    puzzle_subset = models.IntegerField(db_index=True)
-    created = models.DateTimeField(auto_now_add=True)
-
-    def __unicode__(self):
-        return "PuzzleComplete({0}, id={1}, set={2}, subset={3}, created={4})".format(
-            self.user.username, self.puzzle_id,
-            self.puzzle_set, self.puzzle_subset,
-            self.created)
-
-    @staticmethod
-    def completed_puzzles(anonymous_user_id):
-        """
-        Return a list of puzzles that this user has completed, as an array of
-        dicts:
-
-        [ {'set': int,
-           'subset': int,
-           'created': datetime} ]
-        """
-        complete = PuzzleComplete.objects.filter(unique_user_id=anonymous_user_id)
-        return [{'set': c.puzzle_set,
-                 'subset': c.puzzle_subset,
-                 'created': c.created} for c in complete]
-
-    @staticmethod
-    def is_level_complete(anonymous_user_id, level, sub_level, due=None):
-        """
-        Return True if this user completed level--sub_level by due.
-
-        Users see levels as e.g. 4-5.
-
-        Args:
-            level: int
-            sub_level: int
-            due (optional): If specified, a datetime.  Ignored if None.
-        """
-        complete = PuzzleComplete.objects.filter(unique_user_id=anonymous_user_id,
-                                                 puzzle_set=level,
-                                                 puzzle_subset=sub_level)
-        if due is not None:
-            complete = complete.filter(created__lte=due)
-
-        return complete.exists()
diff --git a/lms/djangoapps/foldit/tests.py b/lms/djangoapps/foldit/tests.py
deleted file mode 100644
index 2ff6da98f5c..00000000000
--- a/lms/djangoapps/foldit/tests.py
+++ /dev/null
@@ -1,403 +0,0 @@
-"""Tests for the FoldIt module"""
-import json
-import logging
-from functools import partial
-
-from django.test import TestCase
-from django.test.client import RequestFactory
-from django.core.urlresolvers import reverse
-
-from foldit.views import foldit_ops, verify_code
-from foldit.models import PuzzleComplete, Score
-from student.models import unique_id_for_user, CourseEnrollment
-from student.tests.factories import UserFactory
-
-from datetime import datetime, timedelta
-from pytz import UTC
-from opaque_keys.edx.locations import SlashSeparatedCourseKey
-
-log = logging.getLogger(__name__)
-
-
-class FolditTestCase(TestCase):
-    """Tests for various responses of the FoldIt module"""
-    def setUp(self):
-        super(FolditTestCase, self).setUp()
-
-        self.factory = RequestFactory()
-        self.url = reverse('foldit_ops')
-
-        self.course_id = SlashSeparatedCourseKey('course', 'id', '1')
-        self.course_id2 = SlashSeparatedCourseKey('course', 'id', '2')
-
-        self.user = UserFactory.create()
-        self.user2 = UserFactory.create()
-
-        CourseEnrollment.enroll(self.user, self.course_id)
-        CourseEnrollment.enroll(self.user2, self.course_id2)
-
-        now = datetime.now(UTC)
-        self.tomorrow = now + timedelta(days=1)
-        self.yesterday = now - timedelta(days=1)
-
-    def make_request(self, post_data, user=None):
-        """Makes a request to foldit_ops with the given post data and user (if specified)"""
-        request = self.factory.post(self.url, post_data)
-        request.user = self.user if not user else user
-        return request
-
-    def make_puzzle_score_request(self, puzzle_ids, best_scores, user=None):
-        """
-        Given lists of puzzle_ids and best_scores (must have same length), make a
-        SetPlayerPuzzleScores request and return the response.
-        """
-        if not isinstance(best_scores, list):
-            best_scores = [best_scores]
-        if not isinstance(puzzle_ids, list):
-            puzzle_ids = [puzzle_ids]
-        user = self.user if not user else user
-
-        def score_dict(puzzle_id, best_score):
-            """Returns a valid json-parsable score dict"""
-            return {"PuzzleID": puzzle_id,
-                    "ScoreType": "score",
-                    "BestScore": best_score,
-                    # current scores don't actually matter
-                    "CurrentScore": best_score + 0.01,
-                    "ScoreVersion": 23}
-        scores = [score_dict(pid, bs) for pid, bs in zip(puzzle_ids, best_scores)]
-        scores_str = json.dumps(scores)
-
-        verify = {"Verify": verify_code(user.email, scores_str),
-                  "VerifyMethod": "FoldItVerify"}
-        data = {'SetPlayerPuzzleScoresVerify': json.dumps(verify),
-                'SetPlayerPuzzleScores': scores_str}
-
-        request = self.make_request(data, user)
-
-        response = foldit_ops(request)
-        self.assertEqual(response.status_code, 200)
-        return response
-
-    def test_SetPlayerPuzzleScores(self):  # pylint: disable=invalid-name
-
-        puzzle_id = 994391
-        best_score = 0.078034
-        response = self.make_puzzle_score_request(puzzle_id, [best_score])
-
-        self.assertEqual(response.content, json.dumps(
-            [{"OperationID": "SetPlayerPuzzleScores",
-              "Value": [{
-                  "PuzzleID": puzzle_id,
-                  "Status": "Success"}]}]))
-
-        # There should now be a score in the db.
-        top_10 = Score.get_tops_n(10, puzzle_id)
-        self.assertEqual(len(top_10), 1)
-        self.assertEqual(top_10[0]['score'], Score.display_score(best_score))
-
-    def test_SetPlayerPuzzleScores_many(self):  # pylint: disable=invalid-name
-
-        response = self.make_puzzle_score_request([1, 2], [0.078034, 0.080000])
-
-        self.assertEqual(response.content, json.dumps(
-            [{
-                "OperationID": "SetPlayerPuzzleScores",
-                "Value": [
-                    {
-                        "PuzzleID": 1,
-                        "Status": "Success"
-                    }, {
-                        "PuzzleID": 2,
-                        "Status": "Success"
-                    }
-                ]
-            }]
-        ))
-
-    def test_SetPlayerPuzzleScores_multiple(self):  # pylint: disable=invalid-name
-        """
-        Check that multiple posts with the same id are handled properly
-        (keep latest for each user, have multiple users work properly)
-        """
-        orig_score = 0.07
-        puzzle_id = '1'
-        self.make_puzzle_score_request([puzzle_id], [orig_score])
-
-        # There should now be a score in the db.
-        top_10 = Score.get_tops_n(10, puzzle_id)
-        self.assertEqual(len(top_10), 1)
-        self.assertEqual(top_10[0]['score'], Score.display_score(orig_score))
-
-        # Reporting a better score should overwrite
-        better_score = 0.06
-        self.make_puzzle_score_request([1], [better_score])
-
-        top_10 = Score.get_tops_n(10, puzzle_id)
-        self.assertEqual(len(top_10), 1)
-
-        # Floats always get in the way, so do almostequal
-        self.assertAlmostEqual(
-            top_10[0]['score'],
-            Score.display_score(better_score),
-            delta=0.5
-        )
-
-        # reporting a worse score shouldn't
-        worse_score = 0.065
-        self.make_puzzle_score_request([1], [worse_score])
-
-        top_10 = Score.get_tops_n(10, puzzle_id)
-        self.assertEqual(len(top_10), 1)
-        # should still be the better score
-        self.assertAlmostEqual(
-            top_10[0]['score'],
-            Score.display_score(better_score),
-            delta=0.5
-        )
-
-    def test_SetPlayerPuzzleScores_multiple_courses(self):  # pylint: disable=invalid-name
-        puzzle_id = "1"
-
-        player1_score = 0.05
-        player2_score = 0.06
-
-        course_list_1 = [self.course_id]
-        course_list_2 = [self.course_id2]
-
-        self.make_puzzle_score_request(puzzle_id, player1_score, self.user)
-
-        course_1_top_10 = Score.get_tops_n(10, puzzle_id, course_list_1)
-        course_2_top_10 = Score.get_tops_n(10, puzzle_id, course_list_2)
-        total_top_10 = Score.get_tops_n(10, puzzle_id)
-
-        #  player1 should now be in the top 10 of course 1 and not in course 2
-        self.assertEqual(len(course_1_top_10), 1)
-        self.assertEqual(len(course_2_top_10), 0)
-        self.assertEqual(len(total_top_10), 1)
-
-        self.make_puzzle_score_request(puzzle_id, player2_score, self.user2)
-
-        course_2_top_10 = Score.get_tops_n(10, puzzle_id, course_list_2)
-        total_top_10 = Score.get_tops_n(10, puzzle_id)
-
-        #  player2 should now be in the top 10 of course 2 and not in course 1
-        self.assertEqual(len(course_1_top_10), 1)
-        self.assertEqual(len(course_2_top_10), 1)
-        self.assertEqual(len(total_top_10), 2)
-
-    def test_SetPlayerPuzzleScores_many_players(self):  # pylint: disable=invalid-name
-        """
-        Check that when we send scores from multiple users, the correct order
-        of scores is displayed. Note that, before being processed by
-        display_score, lower scores are better.
-        """
-        puzzle_id = ['1']
-        player1_score = 0.08
-        player2_score = 0.02
-        self.make_puzzle_score_request(puzzle_id, player1_score, self.user)
-
-        # There should now be a score in the db.
-        top_10 = Score.get_tops_n(10, puzzle_id)
-        self.assertEqual(len(top_10), 1)
-        self.assertEqual(top_10[0]['score'], Score.display_score(player1_score))
-
-        self.make_puzzle_score_request(puzzle_id, player2_score, self.user2)
-
-        # There should now be two scores in the db
-        top_10 = Score.get_tops_n(10, puzzle_id)
-        self.assertEqual(len(top_10), 2)
-
-        # Top score should be player2_score. Second should be player1_score
-        self.assertAlmostEqual(
-            top_10[0]['score'],
-            Score.display_score(player2_score),
-            delta=0.5
-        )
-        self.assertAlmostEqual(
-            top_10[1]['score'],
-            Score.display_score(player1_score),
-            delta=0.5
-        )
-
-        # Top score user should be self.user2.username
-        self.assertEqual(top_10[0]['username'], self.user2.username)
-
-    def test_SetPlayerPuzzleScores_error(self):  # pylint: disable=invalid-name
-
-        scores = [{
-            "PuzzleID": 994391,
-            "ScoreType": "score",
-            "BestScore": 0.078034,
-            "CurrentScore": 0.080035,
-            "ScoreVersion": 23
-        }]
-        validation_str = json.dumps(scores)
-
-        verify = {
-            "Verify": verify_code(self.user.email, validation_str),
-            "VerifyMethod": "FoldItVerify"
-        }
-
-        # change the real string -- should get an error
-        scores[0]['ScoreVersion'] = 22
-        scores_str = json.dumps(scores)
-
-        data = {
-            'SetPlayerPuzzleScoresVerify': json.dumps(verify),
-            'SetPlayerPuzzleScores': scores_str
-        }
-
-        request = self.make_request(data)
-
-        response = foldit_ops(request)
-        self.assertEqual(response.status_code, 200)
-
-        self.assertEqual(response.content,
-                         json.dumps([{
-                             "OperationID": "SetPlayerPuzzleScores",
-                             "Success": "false",
-                             "ErrorString": "Verification failed",
-                             "ErrorCode": "VerifyFailed"}]))
-
-    def make_puzzles_complete_request(self, puzzles):
-        """
-        Make a puzzles complete request, given an array of
-        puzzles.  E.g.
-
-        [ {"PuzzleID": 13, "Set": 1, "SubSet": 2},
-          {"PuzzleID": 53524, "Set": 1, "SubSet": 1} ]
-        """
-        puzzles_str = json.dumps(puzzles)
-
-        verify = {
-            "Verify": verify_code(self.user.email, puzzles_str),
-            "VerifyMethod": "FoldItVerify"
-        }
-
-        data = {
-            'SetPuzzlesCompleteVerify': json.dumps(verify),
-            'SetPuzzlesComplete': puzzles_str
-        }
-
-        request = self.make_request(data)
-
-        response = foldit_ops(request)
-        self.assertEqual(response.status_code, 200)
-        return response
-
-    @staticmethod
-    def set_puzzle_complete_response(values):
-        """Returns a json response of a Puzzle Complete message"""
-        return json.dumps([{"OperationID": "SetPuzzlesComplete",
-                            "Value": values}])
-
-    def test_SetPlayerPuzzlesComplete(self):  # pylint: disable=invalid-name
-
-        puzzles = [
-            {"PuzzleID": 13, "Set": 1, "SubSet": 2},
-            {"PuzzleID": 53524, "Set": 1, "SubSet": 1}
-        ]
-
-        response = self.make_puzzles_complete_request(puzzles)
-
-        self.assertEqual(response.content,
-                         self.set_puzzle_complete_response([13, 53524]))
-
-    def test_SetPlayerPuzzlesComplete_multiple(self):  # pylint: disable=invalid-name
-        """Check that state is stored properly"""
-
-        puzzles = [
-            {"PuzzleID": 13, "Set": 1, "SubSet": 2},
-            {"PuzzleID": 53524, "Set": 1, "SubSet": 1}
-        ]
-
-        response = self.make_puzzles_complete_request(puzzles)
-
-        self.assertEqual(response.content,
-                         self.set_puzzle_complete_response([13, 53524]))
-
-        puzzles = [
-            {"PuzzleID": 14, "Set": 1, "SubSet": 3},
-            {"PuzzleID": 15, "Set": 1, "SubSet": 1}
-        ]
-
-        response = self.make_puzzles_complete_request(puzzles)
-
-        self.assertEqual(
-            response.content,
-            self.set_puzzle_complete_response([13, 14, 15, 53524])
-        )
-
-    def test_SetPlayerPuzzlesComplete_level_complete(self):  # pylint: disable=invalid-name
-        """Check that the level complete function works"""
-
-        puzzles = [
-            {"PuzzleID": 13, "Set": 1, "SubSet": 2},
-            {"PuzzleID": 53524, "Set": 1, "SubSet": 1}
-        ]
-
-        response = self.make_puzzles_complete_request(puzzles)
-
-        self.assertEqual(response.content,
-                         self.set_puzzle_complete_response([13, 53524]))
-
-        puzzles = [
-            {"PuzzleID": 14, "Set": 1, "SubSet": 3},
-            {"PuzzleID": 15, "Set": 1, "SubSet": 1}
-        ]
-
-        response = self.make_puzzles_complete_request(puzzles)
-
-        self.assertEqual(response.content,
-                         self.set_puzzle_complete_response([13, 14, 15, 53524]))
-
-        is_complete = partial(
-            PuzzleComplete.is_level_complete, unique_id_for_user(self.user))
-
-        self.assertTrue(is_complete(1, 1))
-        self.assertTrue(is_complete(1, 3))
-        self.assertTrue(is_complete(1, 2))
-        self.assertFalse(is_complete(4, 5))
-
-        puzzles = [{"PuzzleID": 74, "Set": 4, "SubSet": 5}]
-
-        response = self.make_puzzles_complete_request(puzzles)
-
-        self.assertTrue(is_complete(4, 5))
-
-        # Now check due dates
-
-        self.assertTrue(is_complete(1, 1, due=self.tomorrow))
-        self.assertFalse(is_complete(1, 1, due=self.yesterday))
-
-    def test_SetPlayerPuzzlesComplete_error(self):  # pylint: disable=invalid-name
-
-        puzzles = [
-            {"PuzzleID": 13, "Set": 1, "SubSet": 2},
-            {"PuzzleID": 53524, "Set": 1, "SubSet": 1}
-        ]
-
-        puzzles_str = json.dumps(puzzles)
-
-        verify = {
-            "Verify": verify_code(self.user.email, puzzles_str + "x"),
-            "VerifyMethod": "FoldItVerify"
-        }
-
-        data = {
-            'SetPuzzlesCompleteVerify': json.dumps(verify),
-            'SetPuzzlesComplete': puzzles_str
-        }
-
-        request = self.make_request(data)
-
-        response = foldit_ops(request)
-        self.assertEqual(response.status_code, 200)
-
-        self.assertEqual(response.content,
-                         json.dumps([{
-                             "OperationID": "SetPuzzlesComplete",
-                             "Success": "false",
-                             "ErrorString": "Verification failed",
-                             "ErrorCode": "VerifyFailed"}]))
diff --git a/lms/djangoapps/foldit/views.py b/lms/djangoapps/foldit/views.py
deleted file mode 100644
index 91423bbf887..00000000000
--- a/lms/djangoapps/foldit/views.py
+++ /dev/null
@@ -1,175 +0,0 @@
-import hashlib
-import json
-import logging
-
-from django.contrib.auth.decorators import login_required
-from django.http import HttpResponse
-from django.views.decorators.http import require_POST
-from django.views.decorators.csrf import csrf_exempt
-
-from foldit.models import Score, PuzzleComplete
-from student.models import unique_id_for_user
-
-import re
-
-log = logging.getLogger(__name__)
-
-
-@login_required
-@csrf_exempt
-@require_POST
-def foldit_ops(request):
-    """
-    Endpoint view for foldit operations.
-    """
-    responses = []
-    if "SetPlayerPuzzleScores" in request.POST:
-        puzzle_scores_json = request.POST.get("SetPlayerPuzzleScores")
-        pz_verify_json = request.POST.get("SetPlayerPuzzleScoresVerify")
-        log.debug("SetPlayerPuzzleScores message: puzzle scores: %r",
-                  puzzle_scores_json)
-
-        puzzle_score_verify = json.loads(pz_verify_json)
-        if not verifies_ok(request.user.email,
-                           puzzle_scores_json, puzzle_score_verify):
-            responses.append({"OperationID": "SetPlayerPuzzleScores",
-                              "Success": "false",
-                              "ErrorString": "Verification failed",
-                              "ErrorCode": "VerifyFailed"})
-            log.warning(
-                "Verification of SetPlayerPuzzleScores failed:"
-                "user %s, scores json %r, verify %r",
-                request.user,
-                puzzle_scores_json,
-                pz_verify_json
-            )
-        else:
-            # This is needed because we are not getting valid json - the
-            # value of ScoreType is an unquoted string. Right now regexes are
-            # quoting the string, but ideally the json itself would be fixed.
-            # To allow for fixes without breaking this, the regex should only
-            # match unquoted strings,
-            a = re.compile(r':([a-zA-Z]*),')
-            puzzle_scores_json = re.sub(a, r':"\g<1>",', puzzle_scores_json)
-            puzzle_scores = json.loads(puzzle_scores_json)
-            responses.append(save_scores(request.user, puzzle_scores))
-
-    if "SetPuzzlesComplete" in request.POST:
-        puzzles_complete_json = request.POST.get("SetPuzzlesComplete")
-        pc_verify_json = request.POST.get("SetPuzzlesCompleteVerify")
-
-        log.debug("SetPuzzlesComplete message: %r",
-                  puzzles_complete_json)
-
-        puzzles_complete_verify = json.loads(pc_verify_json)
-
-        if not verifies_ok(request.user.email,
-                           puzzles_complete_json, puzzles_complete_verify):
-            responses.append({"OperationID": "SetPuzzlesComplete",
-                              "Success": "false",
-                              "ErrorString": "Verification failed",
-                              "ErrorCode": "VerifyFailed"})
-            log.warning(
-                "Verification of SetPuzzlesComplete failed:"
-                " user %s, puzzles json %r, verify %r",
-                request.user,
-                puzzles_complete_json,
-                pc_verify_json
-            )
-        else:
-            puzzles_complete = json.loads(puzzles_complete_json)
-            responses.append(save_complete(request.user, puzzles_complete))
-
-    return HttpResponse(json.dumps(responses))
-
-
-def verify_code(email, val):
-    """
-    Given the email and passed in value (str), return the expected
-    verification code.
-    """
-    # TODO: is this the right string?
-    verification_string = email.lower() + '|' + val
-    return hashlib.md5(verification_string).hexdigest()
-
-
-def verifies_ok(email, val, verification):
-    """
-    Check that the hash_str matches the expected hash of val.
-
-    Returns True if verification ok, False otherwise
-    """
-    if verification.get("VerifyMethod") != "FoldItVerify":
-        log.debug("VerificationMethod in %r isn't FoldItVerify", verification)
-        return False
-    hash_str = verification.get("Verify")
-
-    return verify_code(email, val) == hash_str
-
-
-def save_scores(user, puzzle_scores):
-    score_responses = []
-    for score in puzzle_scores:
-        log.debug("score: %s", score)
-        # expected keys ScoreType, PuzzleID (int),
-        # BestScore (energy), CurrentScore (Energy), ScoreVersion (int)
-
-        puzzle_id = score['PuzzleID']
-        best_score = score['BestScore']
-        current_score = score['CurrentScore']
-        score_version = score['ScoreVersion']
-
-        # SetPlayerPuzzleScoreResponse object
-        # Score entries are unique on user/unique_user_id/puzzle_id/score_version
-        try:
-            obj = Score.objects.get(
-                user=user,
-                unique_user_id=unique_id_for_user(user),
-                puzzle_id=puzzle_id,
-                score_version=score_version)
-            obj.current_score = current_score
-            obj.best_score = best_score
-
-        except Score.DoesNotExist:
-            obj = Score(
-                user=user,
-                unique_user_id=unique_id_for_user(user),
-                puzzle_id=puzzle_id,
-                current_score=current_score,
-                best_score=best_score,
-                score_version=score_version)
-        obj.save()
-
-        score_responses.append({'PuzzleID': puzzle_id,
-                                'Status': 'Success'})
-
-    return {"OperationID": "SetPlayerPuzzleScores", "Value": score_responses}
-
-
-def save_complete(user, puzzles_complete):
-    """
-    Returned list of PuzzleIDs should be in sorted order (I don't think client
-    cares, but tests do)
-    """
-    for complete in puzzles_complete:
-        log.debug("Puzzle complete: %s", complete)
-        puzzle_id = complete['PuzzleID']
-        puzzle_set = complete['Set']
-        puzzle_subset = complete['SubSet']
-
-        # create if not there
-        PuzzleComplete.objects.get_or_create(
-            user=user,
-            unique_user_id=unique_id_for_user(user),
-            puzzle_id=puzzle_id,
-            puzzle_set=puzzle_set,
-            puzzle_subset=puzzle_subset)
-
-    # List of all puzzle ids of intro-level puzzles completed ever, including on this
-    # request
-    # TODO: this is just in this request...
-
-    complete_responses = list(pc.puzzle_id
-                              for pc in PuzzleComplete.objects.filter(user=user))
-
-    return {"OperationID": "SetPuzzlesComplete", "Value": complete_responses}
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 66f47211f71..c558c53d459 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -1872,9 +1872,6 @@ INSTALLED_APPS = (
     #'wiki.plugins.notifications',
     'course_wiki.plugins.markdownedx',
 
-    # Foldit integration
-    'foldit',
-
     # For testing
     'django.contrib.admin',  # only used in DEBUG mode
     'django_nose',
diff --git a/lms/static/sass/course/courseware/_courseware.scss b/lms/static/sass/course/courseware/_courseware.scss
index e7527fc04d3..cbcfa0849c7 100644
--- a/lms/static/sass/course/courseware/_courseware.scss
+++ b/lms/static/sass/course/courseware/_courseware.scss
@@ -647,17 +647,3 @@ section.self-assessment {
     font-weight: bold;
   }
 }
-
-section.foldit {
-  table {
-    margin-top: ($baseline/2);
-  }
-  th {
-    text-align: center;
-  }
-  td {
-    padding-left: ($baseline/4);
-    padding-right: ($baseline/4);
-
-  }
-}
diff --git a/lms/templates/foldit.html b/lms/templates/foldit.html
deleted file mode 100644
index 2a8271cc62a..00000000000
--- a/lms/templates/foldit.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<section class="foldit">
- 
-    % if show_basic:
-    ${folditbasic}
-    % endif
-
-
-    % if show_leader:
-    ${folditchallenge}
-    % endif
-
-</section>
diff --git a/lms/templates/folditbasic.html b/lms/templates/folditbasic.html
deleted file mode 100644
index 909ffb3b01d..00000000000
--- a/lms/templates/folditbasic.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<%!
-from django.utils.translation import ugettext as _
-from util.date_utils import get_default_time_display
-%>
-<div class="folditbasic">
-<p><strong>${_("Due:")}</strong> ${get_default_time_display(due)}
-
-<p>
-  <strong>${_("Status:")}</strong>
-  % if success:
-  ${_('You have successfully gotten to level {goal_level}.').format(goal_level=goal_level)}'
-  % else:
-  ${_('You have not yet gotten to level {goal_level}.').format(goal_level=goal_level)}
-  % endif
-</p>
-
-<h3>${_("Completed puzzles")}</h3>
-
-<table>
-  <tr>
-    <th>${_("Level")}</th>
-    <th>${_("Submitted")}</th>
-  </tr>
-  % for puzzle in completed:
-  <tr>
-    <td>${'{0}-{1}'.format(puzzle['set'], puzzle['subset'])}</td>
-    <td>${puzzle['created'].strftime('%Y-%m-%d %H:%M')}</td>
-  </tr>
-  % endfor
-</table>
-
-</br>
-</div>
diff --git a/lms/templates/folditchallenge.html b/lms/templates/folditchallenge.html
deleted file mode 100644
index 36e8f0caee1..00000000000
--- a/lms/templates/folditchallenge.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<%! from django.utils.translation import ugettext as _ %>
-
-<div class="folditchallenge">
-    <h3>${_("Puzzle Leaderboard")}</h3>
-    
-    <table>
-        <tr>
-            <th>${_("User")}</th>
-            <th>${_("Score")}</th>
-        </tr>
-        % for pair in top_scores:
-        <tr>
-            <td>${pair[0]}</td>
-            <td>${pair[1]}</td>
-        </tr>
-        % endfor
-    </table>
-</div>
diff --git a/lms/urls.py b/lms/urls.py
index 0f32ac6de80..fdd13a71059 100644
--- a/lms/urls.py
+++ b/lms/urls.py
@@ -651,12 +651,6 @@ if settings.FEATURES.get('RUN_AS_ANALYTICS_SERVER_ENABLED'):
         url(r'^edinsights_service/', include('edinsights.core.urls')),
     )
 
-# FoldIt views
-urlpatterns += (
-    # The path is hardcoded into their app...
-    url(r'^comm/foldit_ops', 'foldit.views.foldit_ops', name="foldit_ops"),
-)
-
 if settings.FEATURES.get('ENABLE_DEBUG_RUN_PYTHON'):
     urlpatterns += (
         url(r'^debug/run_python$', 'debug.views.run_python'),
-- 
GitLab