~jcsackett/charmworld/bac-tag-constraints

« back to all changes in this revision

Viewing changes to charmworld/models.py

  • Committer: Tarmac
  • Author(s): Aaron Bentley
  • Date: 2013-08-06 21:06:58 UTC
  • mfrom: (328.2.13 separate-qa)
  • Revision ID: tarmac-20130806210658-6eau0bkn7o9rmspo
[r=benji][bug=][author=abentley] Separate QA answers from other data.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
# licensed under the GNU Affero General Public License version 3 (see
3
3
# the file LICENSE).
4
4
 
 
5
__metaclass__ = type
 
6
 
5
7
from bzrlib.branch import Branch
6
8
from bzrlib.errors import NoSuchRevision
7
9
from calendar import timegm
89
91
    return user_data
90
92
 
91
93
 
92
 
class UserMgr(object):
 
94
class UserMgr:
93
95
    """Handle non-instance user actions."""
94
96
 
95
97
    @staticmethod
130
132
        return User(user_id, **user_data)
131
133
 
132
134
 
133
 
class User(object):
 
135
class User:
134
136
    """A user in our system."""
135
137
 
136
138
    # Attributes are defined as a list so we can easily create a
192
194
        charm_data['store_data']['revision'])
193
195
 
194
196
 
195
 
class Charm(object):
 
197
class Charm:
196
198
    """A model to access a charm representation.
197
199
 
198
200
    A charm representation is constructed from several processes which
262
264
        'summary': '',
263
265
 
264
266
        # Provided by forms used by ~charmers.
265
 
        'qa': None,
266
267
        'is_featured': False,
267
268
    }
268
269
 
652
653
        return self._representation['short_url']
653
654
 
654
655
    @property
655
 
    def qa(self):
656
 
        """The charm's dict of QA scores."""
657
 
        return self._representation['qa']
658
 
 
659
 
    @property
660
656
    def is_featured(self):
661
657
        """Is this charm featured in the interesting view?"""
662
658
        return self._representation['is_featured']
667
663
        return [change for change in self.changes if change['created'] >= date]
668
664
 
669
665
 
670
 
class QAData(object):
671
 
    """Build a usable object out of the QA questions and instance data."""
672
 
 
673
 
    def _load_questionset(self):
 
666
class QADataSource:
 
667
 
 
668
    def __init__(self, questions, answers):
 
669
        self.questions = questions
 
670
        self.answers = answers
 
671
 
 
672
    @classmethod
 
673
    def from_db(cls, db):
 
674
        return cls(db.qa, db.charm_qa_answers)
 
675
 
 
676
    def load_question_set(self):
674
677
        """Load the qa questions we want to have data about."""
675
 
        stored_questions = self.db.qa.find()
 
678
        stored_questions = self.questions.find()
676
679
        # We index them for easy fetching of each categories data later.
677
 
        self.qa_categories = dict([(q['name'], q) for q in stored_questions])
678
 
 
679
 
    def __init__(self, db, charm_data=None):
680
 
        self.db = db
681
 
        self._load_questionset()
 
680
        return dict([(q['name'], q) for q in stored_questions])
 
681
 
 
682
    def save_qa_data(self, charm, qa_data):
 
683
        charm_id = construct_charm_id(charm._representation)
 
684
        document = {
 
685
            '_id': charm_id,
 
686
            'owner': charm.owner,
 
687
            'series': charm.series,
 
688
            'name': charm.name,
 
689
            'revision': charm.store_data['revision'],
 
690
            'answers': qa_data,
 
691
        }
 
692
        self.answers.save(document)
 
693
 
 
694
    def get_qa_data(self, charm):
 
695
        """Return the QA data that appplies to this charm.
 
696
 
 
697
        The newest QA that is not newer than this charm is considered to
 
698
        apply.  Basically, this assumes no regressions.  "newer" is determined
 
699
        by the store revision.
 
700
        """
 
701
        documents = self.answers.find({
 
702
            'name': charm.name,
 
703
            'series': charm.series,
 
704
            'owner': charm.owner,
 
705
            'revision': {'$lte': charm.store_data['revision']},
 
706
        }).sort('revision', pymongo.DESCENDING).limit(1)
 
707
        if documents.count() == 0:
 
708
            answers = None
 
709
        else:
 
710
            answers = documents[0]['answers']
 
711
        return QAData(self, answers)
 
712
 
 
713
 
 
714
class QAData:
 
715
    """Build a usable object out of the QA questions and instance data."""
 
716
 
 
717
    def __init__(self, qa_data_source, charm_data=None):
 
718
        self.qa_categories = qa_data_source.load_question_set()
682
719
        self.charm_data = charm_data
683
720
 
684
721
    @property
739
776
        return score_categories
740
777
 
741
778
 
742
 
class CharmFileSet(object):
 
779
class CharmFileSet:
743
780
    """Handle Charm file storage and access.
744
781
 
745
782
    Charm key - series/owner/name/bname [branch name: trunk]
918
955
                fs, tree, cls.find_files(tree, logger))
919
956
 
920
957
 
921
 
class CharmFile(object):
 
958
class CharmFile:
922
959
    """Representation of the GridFS stored document.
923
960
 
924
961
    Wraps a PyMongo GridOut object instance.
1116
1153
        self.collection.database.create_collection(self.collection.name)
1117
1154
 
1118
1155
 
1119
 
class Bundle(object):
 
1156
class Bundle:
1120
1157
    """A model to represent bundles of charms."""
1121
1158
 
1122
1159
    _COMMON_REPRESENTATION = {