mirror of https://github.com/zulip/zulip.git
[schema][manual] Automatically subscribe users to default streams only after tutorial
(imported from commit 6511851c0aee2628bef597bf1310d6f96b0fd1d4)
This commit is contained in:
parent
7ce6154464
commit
8fe82085c4
|
@ -89,6 +89,7 @@ urlpatterns += patterns('zephyr.views',
|
|||
url(r'^json/update_active_status$', 'json_update_active_status'),
|
||||
url(r'^json/get_active_statuses$', 'json_get_active_statuses'),
|
||||
url(r'^json/tutorial_send_message$', 'json_tutorial_send_message'),
|
||||
url(r'^json/tutorial_status$', 'json_tutorial_status'),
|
||||
url(r'^json/change_enter_sends$', 'json_change_enter_sends'),
|
||||
url(r'^json/get_profile$', 'json_get_profile'),
|
||||
url(r'^json/report_error$', 'json_report_error'),
|
||||
|
|
|
@ -5,7 +5,7 @@ from zephyr.models import Realm, Stream, UserProfile, UserActivity, \
|
|||
Subscription, Recipient, Message, UserMessage, valid_stream_name, \
|
||||
DefaultStream, StreamColor, UserPresence, MAX_SUBJECT_LENGTH, \
|
||||
MAX_MESSAGE_LENGTH, get_client, get_stream, get_recipient, get_huddle, \
|
||||
get_user_profile_by_id
|
||||
get_user_profile_by_id, PreregistrationUser
|
||||
from django.db import transaction, IntegrityError
|
||||
from django.db.models import F
|
||||
from django.core.exceptions import ValidationError
|
||||
|
@ -708,6 +708,23 @@ def subscribed_to_stream(user_profile, stream):
|
|||
except Subscription.DoesNotExist:
|
||||
return False
|
||||
|
||||
def do_finish_tutorial(user_profile):
|
||||
user_profile.tutorial_status = UserProfile.TUTORIAL_FINISHED
|
||||
user_profile.save()
|
||||
|
||||
# We want to add the default subs list iff there were no subs
|
||||
try:
|
||||
prereg_user = PreregistrationUser.objects.get(email=user_profile.email)
|
||||
except PreregistrationUser.DoesNotExist:
|
||||
return
|
||||
|
||||
streams = prereg_user.streams.all()
|
||||
if len(streams) == 0:
|
||||
add_default_subs(user_profile)
|
||||
else:
|
||||
for stream in streams:
|
||||
do_add_subscription(user_profile, stream)
|
||||
|
||||
def gather_subscriptions(user_profile):
|
||||
# This is a little awkward because the StreamColor table has foreign keys
|
||||
# to Subscription, but not vice versa, and not all Subscriptions have a
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding field 'UserProfile.tutorial_status'
|
||||
db.add_column('zephyr_userprofile', 'tutorial_status',
|
||||
self.gf('django.db.models.fields.CharField')(default='W', max_length=1),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
if "postgres" in settings.DATABASES["default"]["ENGINE"]:
|
||||
db.execute("ALTER TABLE zephyr_userprofile ALTER COLUMN tutorial_status SET DEFAULT 'W'")
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'UserProfile.tutorial_status'
|
||||
db.delete_column('zephyr_userprofile', 'tutorial_status')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'zephyr.client': {
|
||||
'Meta': {'object_name': 'Client'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30', 'db_index': 'True'})
|
||||
},
|
||||
'zephyr.defaultstream': {
|
||||
'Meta': {'unique_together': "(('realm', 'stream'),)", 'object_name': 'DefaultStream'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Realm']"}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Stream']"})
|
||||
},
|
||||
'zephyr.huddle': {
|
||||
'Meta': {'object_name': 'Huddle'},
|
||||
'huddle_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'zephyr.message': {
|
||||
'Meta': {'object_name': 'Message'},
|
||||
'content': ('django.db.models.fields.TextField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'pub_date': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
|
||||
'recipient': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Recipient']"}),
|
||||
'rendered_content': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||
'rendered_content_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
|
||||
'sender': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"}),
|
||||
'sending_client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Client']"}),
|
||||
'subject': ('django.db.models.fields.CharField', [], {'max_length': '60', 'db_index': 'True'})
|
||||
},
|
||||
'zephyr.mituser': {
|
||||
'Meta': {'object_name': 'MitUser'},
|
||||
'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'status': ('django.db.models.fields.IntegerField', [], {'default': '0'})
|
||||
},
|
||||
'zephyr.preregistrationuser': {
|
||||
'Meta': {'object_name': 'PreregistrationUser'},
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'invited_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'referred_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']", 'null': 'True'}),
|
||||
'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'streams': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['zephyr.Stream']", 'null': 'True', 'symmetrical': 'False'})
|
||||
},
|
||||
'zephyr.realm': {
|
||||
'Meta': {'object_name': 'Realm'},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'restricted_to_domain': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'zephyr.recipient': {
|
||||
'Meta': {'unique_together': "(('type', 'type_id'),)", 'object_name': 'Recipient'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.PositiveSmallIntegerField', [], {'db_index': 'True'}),
|
||||
'type_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'})
|
||||
},
|
||||
'zephyr.stream': {
|
||||
'Meta': {'unique_together': "(('name', 'realm'),)", 'object_name': 'Stream'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'invite_only': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', 'null': 'True', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'db_index': 'True'}),
|
||||
'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Realm']"})
|
||||
},
|
||||
'zephyr.streamcolor': {
|
||||
'Meta': {'object_name': 'StreamColor'},
|
||||
'color': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'subscription': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Subscription']"})
|
||||
},
|
||||
'zephyr.subscription': {
|
||||
'Meta': {'unique_together': "(('user_profile', 'recipient'),)", 'object_name': 'Subscription'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'in_home_view': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'recipient': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Recipient']"}),
|
||||
'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"})
|
||||
},
|
||||
'zephyr.useractivity': {
|
||||
'Meta': {'unique_together': "(('user_profile', 'client', 'query'),)", 'object_name': 'UserActivity'},
|
||||
'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Client']"}),
|
||||
'count': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_visit': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'query': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"})
|
||||
},
|
||||
'zephyr.usermessage': {
|
||||
'Meta': {'unique_together': "(('user_profile', 'message'),)", 'object_name': 'UserMessage'},
|
||||
'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'flags': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Message']"}),
|
||||
'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"})
|
||||
},
|
||||
'zephyr.userpresence': {
|
||||
'Meta': {'unique_together': "(('user_profile', 'client'),)", 'object_name': 'UserPresence'},
|
||||
'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Client']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'status': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '1'}),
|
||||
'timestamp': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"})
|
||||
},
|
||||
'zephyr.userprofile': {
|
||||
'Meta': {'object_name': 'UserProfile'},
|
||||
'api_key': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'enable_desktop_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'enter_sends': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', 'null': 'True', 'blank': 'True'}),
|
||||
'full_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_pointer_updater': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'pointer': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Realm']"}),
|
||||
'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'tutorial_status': ('django.db.models.fields.CharField', [], {'default': "'W'", 'max_length': '1'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['zephyr']
|
|
@ -0,0 +1,170 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
orm.UserProfile.objects.all().update(tutorial_status="F")
|
||||
|
||||
def backwards(self, orm):
|
||||
"Write your backwards methods here."
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'zephyr.client': {
|
||||
'Meta': {'object_name': 'Client'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30', 'db_index': 'True'})
|
||||
},
|
||||
'zephyr.defaultstream': {
|
||||
'Meta': {'unique_together': "(('realm', 'stream'),)", 'object_name': 'DefaultStream'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Realm']"}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Stream']"})
|
||||
},
|
||||
'zephyr.huddle': {
|
||||
'Meta': {'object_name': 'Huddle'},
|
||||
'huddle_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'zephyr.message': {
|
||||
'Meta': {'object_name': 'Message'},
|
||||
'content': ('django.db.models.fields.TextField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'pub_date': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
|
||||
'recipient': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Recipient']"}),
|
||||
'rendered_content': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||
'rendered_content_version': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
|
||||
'sender': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"}),
|
||||
'sending_client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Client']"}),
|
||||
'subject': ('django.db.models.fields.CharField', [], {'max_length': '60', 'db_index': 'True'})
|
||||
},
|
||||
'zephyr.mituser': {
|
||||
'Meta': {'object_name': 'MitUser'},
|
||||
'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'status': ('django.db.models.fields.IntegerField', [], {'default': '0'})
|
||||
},
|
||||
'zephyr.preregistrationuser': {
|
||||
'Meta': {'object_name': 'PreregistrationUser'},
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'invited_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'referred_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']", 'null': 'True'}),
|
||||
'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'streams': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['zephyr.Stream']", 'null': 'True', 'symmetrical': 'False'})
|
||||
},
|
||||
'zephyr.realm': {
|
||||
'Meta': {'object_name': 'Realm'},
|
||||
'domain': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'restricted_to_domain': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'zephyr.recipient': {
|
||||
'Meta': {'unique_together': "(('type', 'type_id'),)", 'object_name': 'Recipient'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.PositiveSmallIntegerField', [], {'db_index': 'True'}),
|
||||
'type_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'})
|
||||
},
|
||||
'zephyr.stream': {
|
||||
'Meta': {'unique_together': "(('name', 'realm'),)", 'object_name': 'Stream'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'invite_only': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', 'null': 'True', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'db_index': 'True'}),
|
||||
'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Realm']"})
|
||||
},
|
||||
'zephyr.streamcolor': {
|
||||
'Meta': {'object_name': 'StreamColor'},
|
||||
'color': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'subscription': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Subscription']"})
|
||||
},
|
||||
'zephyr.subscription': {
|
||||
'Meta': {'unique_together': "(('user_profile', 'recipient'),)", 'object_name': 'Subscription'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'in_home_view': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'recipient': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Recipient']"}),
|
||||
'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"})
|
||||
},
|
||||
'zephyr.useractivity': {
|
||||
'Meta': {'unique_together': "(('user_profile', 'client', 'query'),)", 'object_name': 'UserActivity'},
|
||||
'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Client']"}),
|
||||
'count': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_visit': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'query': ('django.db.models.fields.CharField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"})
|
||||
},
|
||||
'zephyr.usermessage': {
|
||||
'Meta': {'unique_together': "(('user_profile', 'message'),)", 'object_name': 'UserMessage'},
|
||||
'archived': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'flags': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Message']"}),
|
||||
'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"})
|
||||
},
|
||||
'zephyr.userpresence': {
|
||||
'Meta': {'unique_together': "(('user_profile', 'client'),)", 'object_name': 'UserPresence'},
|
||||
'client': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Client']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'status': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '1'}),
|
||||
'timestamp': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.UserProfile']"})
|
||||
},
|
||||
'zephyr.userprofile': {
|
||||
'Meta': {'object_name': 'UserProfile'},
|
||||
'api_key': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'enable_desktop_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'enter_sends': ('django.db.models.fields.NullBooleanField', [], {'default': 'False', 'null': 'True', 'blank': 'True'}),
|
||||
'full_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_pointer_updater': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'pointer': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['zephyr.Realm']"}),
|
||||
'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'tutorial_status': ('django.db.models.fields.CharField', [], {'default': "'W'", 'max_length': '1'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['zephyr']
|
||||
symmetrical = True
|
|
@ -69,6 +69,19 @@ class UserProfile(AbstractBaseUser):
|
|||
enable_desktop_notifications = models.BooleanField(default=True)
|
||||
enter_sends = models.NullBooleanField(default=False)
|
||||
|
||||
TUTORIAL_WAITING = 'W'
|
||||
TUTORIAL_STARTED = 'S'
|
||||
TUTORIAL_FINISHED = 'F'
|
||||
TUTORIAL_STATES = ((TUTORIAL_WAITING, "Waiting"),
|
||||
(TUTORIAL_STARTED, "Started"),
|
||||
(TUTORIAL_FINISHED, "Finished"))
|
||||
|
||||
tutorial_status = models.CharField(default=TUTORIAL_WAITING, choices=TUTORIAL_STATES, max_length=1)
|
||||
|
||||
def tutorial_stream_name(self):
|
||||
return "tutorial-%s" % \
|
||||
(self.email.split('@')[0],)[:Stream.MAX_NAME_LENGTH]
|
||||
|
||||
objects = UserManager()
|
||||
|
||||
def __repr__(self):
|
||||
|
|
|
@ -438,29 +438,66 @@ exports.get_invite_only = function (stream_name) {
|
|||
return sub.invite_only;
|
||||
};
|
||||
|
||||
function populate_subscriptions(subs) {
|
||||
var sub_rows = [];
|
||||
subs.sort(function (a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
subs.forEach(function (elem) {
|
||||
var stream_name = elem.name;
|
||||
var sub = create_sub(stream_name, {color: elem.color, in_home_view: elem.in_home_view,
|
||||
invite_only: elem.invite_only, subscribed: true});
|
||||
add_sub(stream_name, sub);
|
||||
sub_rows.push(sub);
|
||||
});
|
||||
|
||||
return sub_rows;
|
||||
}
|
||||
|
||||
exports.reload_subscriptions = function (opts) {
|
||||
var on_success;
|
||||
opts = $.extend({}, {clear_first: false, custom_callbacks: false}, opts);
|
||||
|
||||
if (! opts.custom_callbacks) {
|
||||
on_success = function (data) {
|
||||
if (data) {
|
||||
populate_subscriptions(data.subscriptions);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (opts.clear_first) {
|
||||
stream_info = [];
|
||||
ui.remove_all_narrow_filters();
|
||||
}
|
||||
|
||||
return $.ajax({
|
||||
type: 'POST',
|
||||
url: '/json/subscriptions/list',
|
||||
dataType: 'json',
|
||||
timeout: 10*1000,
|
||||
success: on_success
|
||||
});
|
||||
};
|
||||
|
||||
exports.setup_page = function () {
|
||||
util.make_loading_indicator($('#subs_page_loading_indicator'));
|
||||
|
||||
var our_subs;
|
||||
var all_streams;
|
||||
function populate_and_fill(stream_data, subscription_data) {
|
||||
var all_streams = [];
|
||||
var our_subs = [];
|
||||
|
||||
function maybe_populate_subscriptions() {
|
||||
// We only execute if both asynchronous queries have returned
|
||||
if (our_subs === undefined || all_streams === undefined) {
|
||||
return;
|
||||
/* arguments are [ "success", statusText, jqXHR ] */
|
||||
if (stream_data.length > 2 && stream_data[2]) {
|
||||
var stream_response = JSON.parse(stream_data[2].responseText);
|
||||
all_streams = stream_response.streams;
|
||||
}
|
||||
if (subscription_data.length > 2 && subscription_data[2]) {
|
||||
var subs_response = JSON.parse(subscription_data[2].responseText);
|
||||
our_subs = subs_response.subscriptions;
|
||||
}
|
||||
|
||||
var sub_rows = [];
|
||||
our_subs.sort(function (a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
our_subs.forEach(function (elem) {
|
||||
var stream_name = elem.name;
|
||||
var sub = create_sub(stream_name, {color: elem.color, in_home_view: elem.in_home_view,
|
||||
invite_only: elem.invite_only, subscribed: true});
|
||||
add_sub(stream_name, sub);
|
||||
sub_rows.push(sub);
|
||||
});
|
||||
var sub_rows = populate_subscriptions(our_subs);
|
||||
|
||||
all_streams.sort();
|
||||
all_streams.forEach(function (stream) {
|
||||
|
@ -480,46 +517,35 @@ exports.setup_page = function () {
|
|||
$('#create_stream_name').focus().select();
|
||||
}
|
||||
|
||||
function failed_listing(xhr, error) {
|
||||
util.destroy_loading_indicator($('#subs_page_loading_indicator'));
|
||||
ui.report_error("Error listing streams or subscriptions", xhr, $("#subscriptions-status"));
|
||||
}
|
||||
|
||||
var requests = [];
|
||||
if (should_list_all_streams()) {
|
||||
// This query must go first to prevent a race when we are not
|
||||
// listing all streams
|
||||
$.ajax({
|
||||
var req = $.ajax({
|
||||
type: 'POST',
|
||||
url: '/json/get_public_streams',
|
||||
dataType: 'json',
|
||||
timeout: 10*1000,
|
||||
success: function (data) {
|
||||
if (data) {
|
||||
all_streams = data.streams;
|
||||
maybe_populate_subscriptions();
|
||||
}
|
||||
},
|
||||
error: function (xhr) {
|
||||
util.destroy_loading_indicator($('#subs_page_loading_indicator'));
|
||||
ui.report_error("Error listing subscriptions", xhr, $("#subscriptions-status"));
|
||||
}
|
||||
timeout: 10*1000
|
||||
});
|
||||
requests.push(req);
|
||||
} else {
|
||||
all_streams = [];
|
||||
// Handing an object to $.when() means that it counts as a 'success' with the
|
||||
// object delivered directly to the callback
|
||||
requests.push({streams: []});
|
||||
$('#create_stream_button').val("Subscribe");
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/json/subscriptions/list',
|
||||
dataType: 'json',
|
||||
timeout: 10*1000,
|
||||
success: function (data) {
|
||||
if (data) {
|
||||
our_subs = data.subscriptions;
|
||||
maybe_populate_subscriptions();
|
||||
}
|
||||
},
|
||||
error: function (xhr) {
|
||||
util.destroy_loading_indicator($('#subs_page_loading_indicator'));
|
||||
ui.report_error("Error listing subscriptions", xhr, $("#subscriptions-status"));
|
||||
}
|
||||
});
|
||||
requests.push(exports.reload_subscriptions({custom_callbacks: true}));
|
||||
|
||||
// Trigger finished callback when:
|
||||
// * Both AJAX requests are finished, if we sent themm both
|
||||
// * Just one AJAX is finished if should_list_all_streams() is false
|
||||
$.when.apply(this, requests).then(populate_and_fill, failed_listing);
|
||||
};
|
||||
|
||||
exports.have = function (stream_name) {
|
||||
|
|
|
@ -240,6 +240,13 @@ exports.start = function () {
|
|||
tutorial_running = true;
|
||||
add_to_tutorial_stream();
|
||||
run_tutorial(0);
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/json/tutorial_status',
|
||||
data: {status: 'started'}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// This technique is not actually that awesome, because it's pretty
|
||||
|
@ -256,6 +263,17 @@ exports.stop = function () {
|
|||
if (tutorial_running) {
|
||||
subs.tutorial_unsubscribe_me_from(my_tutorial_stream);
|
||||
tutorial_running = false;
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/json/tutorial_status',
|
||||
data: {status: 'finished'},
|
||||
success: function () {
|
||||
// We need to reload the streams list so the sidebar is populated
|
||||
// with the new streams
|
||||
subs.reload_subscriptions({clear_first: true});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1167,6 +1167,10 @@ exports.remove_narrow_filter = function (name, type) {
|
|||
exports.get_filter_li(type, name).remove();
|
||||
};
|
||||
|
||||
exports.remove_all_narrow_filters = function () {
|
||||
$("#stream_filters").children().remove();
|
||||
};
|
||||
|
||||
var presence_descriptions = {
|
||||
active: ' is active',
|
||||
away: ' was recently active',
|
||||
|
|
|
@ -25,7 +25,7 @@ from zephyr.lib.actions import do_add_subscription, do_remove_subscription, \
|
|||
log_subscription_property_change, internal_send_message, \
|
||||
create_stream_if_needed, gather_subscriptions, subscribed_to_stream, \
|
||||
update_user_presence, set_stream_color, get_stream_colors, update_message_flags, \
|
||||
recipient_for_emails, extract_recipients, do_events_register
|
||||
recipient_for_emails, extract_recipients, do_events_register, do_finish_tutorial
|
||||
from zephyr.forms import RegistrationForm, HomepageForm, ToSForm, is_unique, \
|
||||
is_inactive, isnt_mit
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
@ -212,14 +212,6 @@ def accounts_register(request):
|
|||
do_change_full_name(user_profile, full_name)
|
||||
else:
|
||||
user_profile = do_create_user(email, password, realm, full_name, short_name)
|
||||
# We want to add the default subs list iff there were no subs
|
||||
# specified when the user was invited.
|
||||
streams = prereg_user.streams.all()
|
||||
if len(streams) == 0:
|
||||
add_default_subs(user_profile)
|
||||
else:
|
||||
for stream in streams:
|
||||
do_add_subscription(user_profile, stream)
|
||||
if prereg_user.referred_by is not None:
|
||||
# This is a cross-realm private message.
|
||||
internal_send_message("humbug+signups@humbughq.com",
|
||||
|
@ -401,9 +393,21 @@ def home(request):
|
|||
register_ret = do_events_register(user_profile, apply_markdown=True)
|
||||
user_has_messages = (register_ret['max_message_id'] != -1)
|
||||
|
||||
# Brand new users get the tutorial.
|
||||
# Compute this here, before we set user_profile.pointer below.
|
||||
needs_tutorial = settings.TUTORIAL_ENABLED and user_profile.pointer == -1
|
||||
# Brand new users get the tutorial
|
||||
needs_tutorial = settings.TUTORIAL_ENABLED and \
|
||||
user_profile.tutorial_status == UserProfile.TUTORIAL_WAITING
|
||||
|
||||
# If the user has previously started (but not completed) the tutorial,
|
||||
# finish it for her and subscribe her to the default streams
|
||||
if user_profile.tutorial_status == UserProfile.TUTORIAL_STARTED:
|
||||
tutorial_stream = user_profile.tutorial_stream_name()
|
||||
try:
|
||||
stream = Stream.objects.get(realm=user_profile.realm, name=tutorial_stream)
|
||||
do_remove_subscription(user_profile, stream)
|
||||
except Stream.DoesNotExist:
|
||||
pass
|
||||
|
||||
do_finish_tutorial(user_profile)
|
||||
|
||||
if user_profile.pointer == -1 and user_has_messages:
|
||||
# Put the new user's pointer at the bottom
|
||||
|
@ -769,8 +773,7 @@ def json_tutorial_send_message(request, user_profile,
|
|||
realm=user_profile.realm)
|
||||
return json_success()
|
||||
elif message_type_name == 'stream':
|
||||
tutorial_stream_name = 'tutorial-%s' % user_profile.email.split('@')[0]
|
||||
tutorial_stream_name = tutorial_stream_name[:Stream.MAX_NAME_LENGTH]
|
||||
tutorial_stream_name = user_profile.tutorial_stream_name()
|
||||
## TODO: For open realms, we need to use the full name here,
|
||||
## so that me@gmail.com and me@hotmail.com don't get the same stream.
|
||||
internal_send_message(sender_name,
|
||||
|
@ -782,6 +785,18 @@ def json_tutorial_send_message(request, user_profile,
|
|||
return json_success()
|
||||
return json_error('Bad data passed in to tutorial_send_message')
|
||||
|
||||
|
||||
@authenticated_json_post_view
|
||||
@has_request_variables
|
||||
def json_tutorial_status(request, user_profile, status=POST('status')):
|
||||
if status == 'started':
|
||||
user_profile.tutorial_status = UserProfile.TUTORIAL_STARTED
|
||||
user_profile.save()
|
||||
elif status == 'finished':
|
||||
do_finish_tutorial(user_profile)
|
||||
|
||||
return json_success()
|
||||
|
||||
# We do not @require_login for send_message_backend, since it is used
|
||||
# both from the API and the web service. Code calling
|
||||
# send_message_backend should either check the API key or check that
|
||||
|
|
Loading…
Reference in New Issue