<commit_before># -*- coding: utf-8 -*-
# Copyright 2014, <NAME>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import logging

from google.appengine.api import channel
from google.appengine.ext import db

import utils


# Profile
# ↳ Client
#
# Instance
#
# Subject
# ↳ Message
# ↳ Pin (⤴︎ Instance)
# ↳ Subscription (⤴︎ Instance)


class DuplicateMessage(Exception):
  pass


class AccessDenied(Exception):
  pass


class Profile(db.Model):
  google_user = db.UserProperty()

  @classmethod
  def FromGoogleUser(cls, google_user):
    if not google_user:
      profile = Profile()
      profile.put()
      return profile

    profiles = Profile.all().filter('google_user =', google_user).fetch(1)
    if profiles:
      return profiles[0]
    else:
      # TODO(flamingcow): Fetch-then-store uniqueness is a race.
      profile = Profile(google_user=google_user)
      profile.put()
      return profile

  def MergeFrom(self, source_profile):
    # This is non-transactional and racy (new messages can be introduced by the
    # old client after we start). This is hard to solve because a) we're not in
    # a single hierarchy and b) we don't revoke the old client ID, so it can
    # still be used.
    for message in Message.all().filter('sender =', source_profile):
      message.sender = self;
      message.put()


class Client(db.Model):
  # parent=Profile

  first_seen = db.DateTimeProperty(required=True, auto_now_add=True)

  @classmethod
  def FromProfile(cls, profile):
    client = cls(parent=profile)
    client.put()
    return client

  @classmethod
  def FromGoogleUser(cls, google_user):
    profile = Profile.FromGoogleUser(google_user)
    return cls.FromProfile(profile)


class Instance(db.Model):
  active = db.BooleanProperty(required=True, default=False)

  @classmethod
  @db.transactional()
  def FromID(cls, instance_id):
    return cls.get_by_key_name(instance_id)

  @classmethod
  @db.transactional()
  def FindOrCreate(cls, instance_id):
    instance = cls.FromID(instance_id)
    if instance:
      return instance
    else:
      return cls(key_name=instance_id).put()


class Subject(db.Model):

  name = db.StringProperty(required=True)
  readable_only_by = db.ReferenceProperty(
      reference_class=Profile, collection_name='readable_subject_set')
  writable_only_by = db.ReferenceProperty(
      reference_class=Profile, collection_name='writable_subject_set')

  next_message_id = db.IntegerProperty(required=True, default=1)

  @classmethod
  def FindOrCreate(cls, subject):
    if 'readable_only_by' in subject:
      readable_only_by = Profile.get(subject['readable_only_by'])
    else:
      readable_only_by = None

    if 'writable_only_by' in subject:<commit_msg>Use get_or_insert for finding instances.<commit_after># -*- coding: utf-8 -*-
# Copyright 2014, <NAME>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import logging

from google.appengine.api import channel
from google.appengine.ext import db

import utils


# Profile
# ↳ Client
#
# Instance
#
# Subject
# ↳ Message
# ↳ Pin (⤴︎ Instance)
# ↳ Subscription (⤴︎ Instance)


class DuplicateMessage(Exception):
  pass


class AccessDenied(Exception):
  pass


class Profile(db.Model):
  google_user = db.UserProperty()

  @classmethod
  def FromGoogleUser(cls, google_user):
    if not google_user:
      profile = Profile()
      profile.put()
      return profile

    profiles = Profile.all().filter('google_user =', google_user).fetch(1)
    if profiles:
      return profiles[0]
    else:
      # TODO(flamingcow): Fetch-then-store uniqueness is a race.
      profile = Profile(google_user=google_user)
      profile.put()
      return profile

  def MergeFrom(self, source_profile):
    # This is non-transactional and racy (new messages can be introduced by the
    # old client after we start). This is hard to solve because a) we're not in
    # a single hierarchy and b) we don't revoke the old client ID, so it can
    # still be used.
    for message in Message.all().filter('sender =', source_profile):
      message.sender = self;
      message.put()


class Client(db.Model):
  # parent=Profile

  first_seen = db.DateTimeProperty(required=True, auto_now_add=True)

  @classmethod
  def FromProfile(cls, profile):
    client = cls(parent=profile)
    client.put()
    return client

  @classmethod
  def FromGoogleUser(cls, google_user):
    profile = Profile.FromGoogleUser(google_user)
    return cls.FromProfile(profile)


class Instance(db.Model):
  # key_name=instance_id
  active = db.BooleanProperty(required=True, default=False)

  @classmethod
  def FromID(cls, instance_id):
    return cls.get_by_key_name(instance_id)

  @classmethod
  def FindOrCreate(cls, instance_id):
    return cls.get_or_insert(instance_id)


class Subject(db.Model):

  name = db.StringProperty(required=True)
  readable_only_by = db.ReferenceProperty(
      reference_class=Profile, collection_name='readable_subject_set')
  writable_only_by = db.ReferenceProperty(
      reference_class=Profile, collection_name='writable_subject_set')

  next_message_id = db.IntegerProperty(required=True, default=1)

  @classmethod
  def FindOrCreate(cls, subject):
    if 'readable_only_by' in subject:
      readable_only_by = Profile.get(subject['readable_only_by'])
    else:
      readable_only_by = None

    if 'writable_only_by' in subject:
{'fraction_non_alphanumeric': 0.09386281588447654, 'fraction_numerical': 0.003767069533825145, 'mean_word_length': 3.9510489510489513, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5471314', 'n_tokens_mistral': 1949, 'n_tokens_neox': 1913, 'n_words': 577}