mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	Add a user-visible setting for 24-hour time display.
(imported from commit d934824fd6b72e64a455aac9ff4585b262145f02)
This commit is contained in:
		@@ -3,12 +3,8 @@ var feature_flags = (function () {
 | 
			
		||||
var exports = {};
 | 
			
		||||
 | 
			
		||||
// Helpers
 | 
			
		||||
var special_24_hour_people= _.contains([],
 | 
			
		||||
    page_params.email);
 | 
			
		||||
var og_zuliper_emails = [];
 | 
			
		||||
 | 
			
		||||
var iceland = page_params.domain === 'customer8.invalid';
 | 
			
		||||
 | 
			
		||||
var customer4_realms = [
 | 
			
		||||
  'customer4.invalid',
 | 
			
		||||
  'users.customer4.invalid'
 | 
			
		||||
@@ -25,7 +21,6 @@ exports.collect_send_times = false;
 | 
			
		||||
// Permanent realm-specific stuff:
 | 
			
		||||
exports.disable_message_editing = _.contains(['mit.edu'], page_params.domain);
 | 
			
		||||
exports.is_og_zulip_user = _.contains(og_zuliper_emails, page_params.email);
 | 
			
		||||
exports.twenty_four_hour_time = special_24_hour_people || iceland;
 | 
			
		||||
 | 
			
		||||
exports.left_side_userlist = _.contains(['customer7.invalid'], page_params.domain);
 | 
			
		||||
exports.enable_new_user_app_alerts = ! _.contains(['employees.customer16.invalid'], page_params.domain);
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ function MessageListView(list, table_name, collapse_messages) {
 | 
			
		||||
(function () {
 | 
			
		||||
 | 
			
		||||
function stringify_time(time) {
 | 
			
		||||
    if (feature_flags.twenty_four_hour_time) {
 | 
			
		||||
    if (page_params.twenty_four_hour_time) {
 | 
			
		||||
        return time.toString('HH:mm');
 | 
			
		||||
    }
 | 
			
		||||
    return time.toString('h:mm TT');
 | 
			
		||||
 
 | 
			
		||||
@@ -180,6 +180,9 @@ function get_events_success(events) {
 | 
			
		||||
            notifications.handle_global_notification_updates(event.notification_name,
 | 
			
		||||
                                                             event.setting);
 | 
			
		||||
            break;
 | 
			
		||||
        case 'update_display_settings':
 | 
			
		||||
            page_params.twenty_four_hour_time = event.twenty_four_hour_time;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -151,6 +151,7 @@ exports.setup_page = function () {
 | 
			
		||||
    $("#settings").html(settings_tab);
 | 
			
		||||
    $("#settings-status").hide();
 | 
			
		||||
    $("#notify-settings-status").hide();
 | 
			
		||||
    $("#display-settings-status").hide();
 | 
			
		||||
    $("#ui-settings-status").hide();
 | 
			
		||||
 | 
			
		||||
    alert_words_ui.set_up_alert_words();
 | 
			
		||||
@@ -383,6 +384,41 @@ exports.setup_page = function () {
 | 
			
		||||
                                                      update_audible_notification_setting);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $("#twenty_four_hour_time").change(function () {
 | 
			
		||||
        var time_checkbox = $("#twenty_four_hour_time").is(":checked");
 | 
			
		||||
        var data = {};
 | 
			
		||||
        data.twenty_four_hour_time = JSON.stringify(time_checkbox);
 | 
			
		||||
 | 
			
		||||
        channel.patch({
 | 
			
		||||
            url: '/json/time_setting',
 | 
			
		||||
            data: data,
 | 
			
		||||
            success: function (resp, statusText, xhr, form) {
 | 
			
		||||
                var message = "Updated display settings!";
 | 
			
		||||
                var result = $.parseJSON(xhr.responseText);
 | 
			
		||||
                var display_settings_status = $('#display-settings-status').expectOne();
 | 
			
		||||
 | 
			
		||||
                display_settings_status.removeClass(status_classes)
 | 
			
		||||
                    .addClass('alert-success')
 | 
			
		||||
                    .text(message).stop(true).fadeTo(0,1);
 | 
			
		||||
                },
 | 
			
		||||
            error: function (xhr, error_type, xhn) {
 | 
			
		||||
                var response = "Error updating display settings";
 | 
			
		||||
                var display_settings_status = $('#display-settings-status').expectOne();
 | 
			
		||||
 | 
			
		||||
                 if (xhr.status.toString().charAt(0) === "4") {
 | 
			
		||||
                    // Only display the error response for 4XX, where we've crafted
 | 
			
		||||
                    // a nice response.
 | 
			
		||||
                    response += ": " + $.parseJSON(xhr.responseText).msg;
 | 
			
		||||
                }
 | 
			
		||||
                display_settings_status.removeClass(status_classes)
 | 
			
		||||
                    .addClass('alert-error')
 | 
			
		||||
                    .text(response).stop(true).fadeTo(0,1);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    $("#get_api_key_box").hide();
 | 
			
		||||
    $("#show_api_key_box").hide();
 | 
			
		||||
    $("#get_api_key_box form").ajaxForm({
 | 
			
		||||
 
 | 
			
		||||
@@ -3299,7 +3299,7 @@ div.edit_bot {
 | 
			
		||||
    position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#settings #notify-settings-status,#ui-settings-status {
 | 
			
		||||
#settings #notify-settings-status,#ui-settings-status,#display-settings-status {
 | 
			
		||||
    width: 80%;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    margin: auto;
 | 
			
		||||
@@ -3324,7 +3324,7 @@ div.edit_bot {
 | 
			
		||||
    left: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#settings .settings-section .notification-settings-form,.ui-settings-form {
 | 
			
		||||
#settings .settings-section .notification-settings-form,.ui-settings-form,.display-settings-form {
 | 
			
		||||
    width: 400px;
 | 
			
		||||
    margin: auto;
 | 
			
		||||
}
 | 
			
		||||
@@ -3343,6 +3343,7 @@ div.edit_bot {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#settings .settings-section .notification-settings-form .controls,
 | 
			
		||||
#settings .settings-section .display-settings-form .controls,
 | 
			
		||||
#settings .settings-section .ui-settings-form .controls {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
@@ -3354,7 +3355,12 @@ div.edit_bot {
 | 
			
		||||
    margin-right: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#settings .settings-section .display-settings-form .controls {
 | 
			
		||||
    margin-left: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#settings .settings-section .notification-settings-form .controls input[type='checkbox'],
 | 
			
		||||
#settings .settings-section .display-settings-form .controls input[type='checkbox'],
 | 
			
		||||
#settings .settings-section .ui-settings-form .controls input[type='checkbox'] {
 | 
			
		||||
    margin: 0px;
 | 
			
		||||
    padding: 0px;
 | 
			
		||||
@@ -3364,7 +3370,8 @@ div.edit_bot {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#settings .settings-section .notification-settings-form .control-label,
 | 
			
		||||
#settings .settings-section .ui-settings-form .control-label {
 | 
			
		||||
#settings .settings-section .ui-settings-form .control-label,
 | 
			
		||||
#settings .settings-section .display-settings-form .control-label {
 | 
			
		||||
    float: none;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
@@ -3373,6 +3380,10 @@ div.edit_bot {
 | 
			
		||||
    width:  240px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#settings .settings-section .display-settings-form .control-label {
 | 
			
		||||
    width:  360px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#settings .settings-section .notification-settings-form .notification-submission,
 | 
			
		||||
#settings .settings-section .ui-settings-form .ui-submission {
 | 
			
		||||
    margin-left: 140px;
 | 
			
		||||
@@ -3477,6 +3488,7 @@ div.edit_bot {
 | 
			
		||||
#settings .settings-section .account-settings-form,
 | 
			
		||||
#settings .settings-section .new-bot-form,
 | 
			
		||||
#settings .settings-section .notification-settings-form,
 | 
			
		||||
#settings .settings-section .display-settings-form,
 | 
			
		||||
#settings .settings-section .edit-bot-form-box {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -86,6 +86,28 @@
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div>
 | 
			
		||||
    <div id="display-settings" class="settings-section">
 | 
			
		||||
      <div class="settings-section-title"><i class="icon-vector-time settings-section-icon"></i>
 | 
			
		||||
      Display Settings</div>
 | 
			
		||||
      <div class="alert" id="display-settings-status"></div>
 | 
			
		||||
      <div class="display-settings-form">
 | 
			
		||||
        <div class="control-group">
 | 
			
		||||
          <div class="controls">
 | 
			
		||||
            <input type="checkbox" name="twenty_four_hour_time"
 | 
			
		||||
                   id="twenty_four_hour_time"
 | 
			
		||||
                   {{#if page_params.twenty_four_hour_time}}
 | 
			
		||||
                   checked="yes"
 | 
			
		||||
                   {{/if}} />
 | 
			
		||||
          </div>
 | 
			
		||||
          <label for="twenty_four_hour_time" class="control-label">
 | 
			
		||||
            Display time in 24-hour format (17:00 instead of 5:00 PM)
 | 
			
		||||
          </label>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div>
 | 
			
		||||
    <div id="notification-settings" class="settings-section">
 | 
			
		||||
      <div class="settings-section-title"><i class="icon-vector-warning-sign settings-section-icon"></i>Notifications</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1717,6 +1717,16 @@ def do_change_default_desktop_notifications(user_profile, default_desktop_notifi
 | 
			
		||||
    user_profile.default_desktop_notifications = default_desktop_notifications
 | 
			
		||||
    user_profile.save(update_fields=["default_desktop_notifications"])
 | 
			
		||||
 | 
			
		||||
def do_change_twenty_four_hour_time(user_profile, twenty_four_hour_time, log=True):
 | 
			
		||||
    user_profile.twenty_four_hour_time = twenty_four_hour_time
 | 
			
		||||
    user_profile.save(update_fields=["twenty_four_hour_time"])
 | 
			
		||||
    event = {'type': 'update_display_settings',
 | 
			
		||||
             'user': user_profile.email,
 | 
			
		||||
             'setting': twenty_four_hour_time}
 | 
			
		||||
    if log:
 | 
			
		||||
        log_event(event)
 | 
			
		||||
    send_event(event, [user_profile.id])
 | 
			
		||||
 | 
			
		||||
def set_default_streams(realm, stream_names):
 | 
			
		||||
    DefaultStream.objects.filter(realm=realm).delete()
 | 
			
		||||
    for stream_name in stream_names:
 | 
			
		||||
@@ -2359,6 +2369,9 @@ def fetch_initial_state_data(user_profile, event_types, queue_id):
 | 
			
		||||
    if want('stream'):
 | 
			
		||||
        state['streams'] = do_get_streams(user_profile)
 | 
			
		||||
 | 
			
		||||
    if want('update_display_settings'):
 | 
			
		||||
        state['twenty_four_hour_time'] = user_profile.twenty_four_hour_time
 | 
			
		||||
 | 
			
		||||
    return state
 | 
			
		||||
 | 
			
		||||
def apply_events(state, events, user_profile):
 | 
			
		||||
@@ -2489,6 +2502,8 @@ def apply_events(state, events, user_profile):
 | 
			
		||||
            state['muted_topics'] = event["muted_topics"]
 | 
			
		||||
        elif event['type'] == "realm_filters":
 | 
			
		||||
            state['realm_filters'] = event["realm_filters"]
 | 
			
		||||
        elif event['type'] == "update_display_settings":
 | 
			
		||||
            state['twenty_four_hour_time'] == event["twenty_four_hour_time"]
 | 
			
		||||
        else:
 | 
			
		||||
            raise ValueError("Unexpected event type %s" % (event['type'],))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,275 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from south.utils import datetime_utils as 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.twenty_four_hour_time'
 | 
			
		||||
        db.add_column(u'zerver_userprofile', 'twenty_four_hour_time',
 | 
			
		||||
                      self.gf('django.db.models.fields.BooleanField')(default=False),
 | 
			
		||||
                      keep_default=True)
 | 
			
		||||
        if settings.DEPLOYED and not settings.ENTERPRISE:
 | 
			
		||||
            db.execute("UPDATE zerver_userprofile SET twenty_four_hour_time = TRUE WHERE realm_id IN " +
 | 
			
		||||
                       "(SELECT id FROM zerver_realm WHERE domain='customer8.invalid')")
 | 
			
		||||
            db.execute("UPDATE zerver_userprofile SET twenty_four_hour_time = TRUE WHERE email IN ()")
 | 
			
		||||
 | 
			
		||||
    def backwards(self, orm):
 | 
			
		||||
        # Deleting field 'UserProfile.twenty_four_hour_time'
 | 
			
		||||
        db.delete_column(u'zerver_userprofile', 'twenty_four_hour_time')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    models = {
 | 
			
		||||
        u'auth.group': {
 | 
			
		||||
            'Meta': {'object_name': 'Group'},
 | 
			
		||||
            u'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': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
 | 
			
		||||
        },
 | 
			
		||||
        u'auth.permission': {
 | 
			
		||||
            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
 | 
			
		||||
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
 | 
			
		||||
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
 | 
			
		||||
        },
 | 
			
		||||
        u'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'}),
 | 
			
		||||
            u'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'})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.appledevicetoken': {
 | 
			
		||||
            'Meta': {'object_name': 'AppleDeviceToken'},
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'last_updated': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
 | 
			
		||||
            'token': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
 | 
			
		||||
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.UserProfile']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.client': {
 | 
			
		||||
            'Meta': {'object_name': 'Client'},
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30', 'db_index': 'True'})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.defaultstream': {
 | 
			
		||||
            'Meta': {'unique_together': "(('realm', 'stream'),)", 'object_name': 'DefaultStream'},
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Realm']"}),
 | 
			
		||||
            'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Stream']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.huddle': {
 | 
			
		||||
            'Meta': {'object_name': 'Huddle'},
 | 
			
		||||
            'huddle_hash': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.message': {
 | 
			
		||||
            'Meta': {'object_name': 'Message'},
 | 
			
		||||
            'content': ('django.db.models.fields.TextField', [], {}),
 | 
			
		||||
            'edit_history': ('django.db.models.fields.TextField', [], {'null': 'True'}),
 | 
			
		||||
            'has_attachment': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
 | 
			
		||||
            'has_image': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
 | 
			
		||||
            'has_link': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'last_edit_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
 | 
			
		||||
            'pub_date': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
 | 
			
		||||
            'recipient': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.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': u"orm['zerver.UserProfile']"}),
 | 
			
		||||
            'sending_client': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Client']"}),
 | 
			
		||||
            'subject': ('django.db.models.fields.CharField', [], {'max_length': '60', 'db_index': 'True'})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.mituser': {
 | 
			
		||||
            'Meta': {'object_name': 'MitUser'},
 | 
			
		||||
            'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'status': ('django.db.models.fields.IntegerField', [], {'default': '0'})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.preregistrationuser': {
 | 
			
		||||
            'Meta': {'object_name': 'PreregistrationUser'},
 | 
			
		||||
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'invited_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
 | 
			
		||||
            'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Realm']", 'null': 'True'}),
 | 
			
		||||
            'referred_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.UserProfile']", 'null': 'True'}),
 | 
			
		||||
            'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
 | 
			
		||||
            'streams': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['zerver.Stream']", 'null': 'True', 'symmetrical': 'False'})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.pushdevicetoken': {
 | 
			
		||||
            'Meta': {'object_name': 'PushDeviceToken'},
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'ios_app_id': ('django.db.models.fields.TextField', [], {'null': 'True'}),
 | 
			
		||||
            'kind': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
 | 
			
		||||
            'last_updated': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'auto_now': 'True', 'blank': 'True'}),
 | 
			
		||||
            'token': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}),
 | 
			
		||||
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.UserProfile']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.realm': {
 | 
			
		||||
            'Meta': {'object_name': 'Realm'},
 | 
			
		||||
            'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
 | 
			
		||||
            'deactivated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'domain': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'invite_by_admins_only': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'invite_required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'mandatory_topics': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True'}),
 | 
			
		||||
            'name_changes_disabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'notifications_stream': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': u"orm['zerver.Stream']"}),
 | 
			
		||||
            'restricted_to_domain': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'show_digest_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.realmalias': {
 | 
			
		||||
            'Meta': {'object_name': 'RealmAlias'},
 | 
			
		||||
            'domain': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80', 'db_index': 'True'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Realm']", 'null': 'True'})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.realmemoji': {
 | 
			
		||||
            'Meta': {'unique_together': "(('realm', 'name'),)", 'object_name': 'RealmEmoji'},
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'img_url': ('django.db.models.fields.TextField', [], {}),
 | 
			
		||||
            'name': ('django.db.models.fields.TextField', [], {}),
 | 
			
		||||
            'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Realm']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.realmfilter': {
 | 
			
		||||
            'Meta': {'unique_together': "(('realm', 'pattern'),)", 'object_name': 'RealmFilter'},
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'pattern': ('django.db.models.fields.TextField', [], {}),
 | 
			
		||||
            'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Realm']"}),
 | 
			
		||||
            'url_format_string': ('django.db.models.fields.TextField', [], {})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.recipient': {
 | 
			
		||||
            'Meta': {'unique_together': "(('type', 'type_id'),)", 'object_name': 'Recipient'},
 | 
			
		||||
            u'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'})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.referral': {
 | 
			
		||||
            'Meta': {'object_name': 'Referral'},
 | 
			
		||||
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
 | 
			
		||||
            'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.UserProfile']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.scheduledjob': {
 | 
			
		||||
            'Meta': {'object_name': 'ScheduledJob'},
 | 
			
		||||
            'data': ('django.db.models.fields.TextField', [], {}),
 | 
			
		||||
            'filter_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
 | 
			
		||||
            'filter_string': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'scheduled_timestamp': ('django.db.models.fields.DateTimeField', [], {}),
 | 
			
		||||
            'type': ('django.db.models.fields.PositiveSmallIntegerField', [], {})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.stream': {
 | 
			
		||||
            'Meta': {'unique_together': "(('name', 'realm'),)", 'object_name': 'Stream'},
 | 
			
		||||
            'date_created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
 | 
			
		||||
            'deactivated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'description': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
 | 
			
		||||
            'email_token': ('django.db.models.fields.CharField', [], {'default': "'db559172cf87493869af805bd51da2d4'", 'max_length': '32'}),
 | 
			
		||||
            u'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': '60', 'db_index': 'True'}),
 | 
			
		||||
            'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Realm']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.streamcolor': {
 | 
			
		||||
            'Meta': {'object_name': 'StreamColor'},
 | 
			
		||||
            'color': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'subscription': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Subscription']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.subscription': {
 | 
			
		||||
            'Meta': {'unique_together': "(('user_profile', 'recipient'),)", 'object_name': 'Subscription'},
 | 
			
		||||
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'audible_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'color': ('django.db.models.fields.CharField', [], {'default': "'#c2c2c2'", 'max_length': '10'}),
 | 
			
		||||
            'desktop_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'in_home_view': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}),
 | 
			
		||||
            'notifications': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'recipient': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Recipient']"}),
 | 
			
		||||
            'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.UserProfile']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.useractivity': {
 | 
			
		||||
            'Meta': {'unique_together': "(('user_profile', 'client', 'query'),)", 'object_name': 'UserActivity'},
 | 
			
		||||
            'client': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Client']"}),
 | 
			
		||||
            'count': ('django.db.models.fields.IntegerField', [], {}),
 | 
			
		||||
            u'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': u"orm['zerver.UserProfile']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.useractivityinterval': {
 | 
			
		||||
            'Meta': {'object_name': 'UserActivityInterval'},
 | 
			
		||||
            'end': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'start': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
 | 
			
		||||
            'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.UserProfile']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.usermessage': {
 | 
			
		||||
            'Meta': {'unique_together': "(('user_profile', 'message'),)", 'object_name': 'UserMessage'},
 | 
			
		||||
            'flags': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'message': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Message']"}),
 | 
			
		||||
            'user_profile': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.UserProfile']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.userpresence': {
 | 
			
		||||
            'Meta': {'unique_together': "(('user_profile', 'client'),)", 'object_name': 'UserPresence'},
 | 
			
		||||
            'client': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Client']"}),
 | 
			
		||||
            u'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': u"orm['zerver.UserProfile']"})
 | 
			
		||||
        },
 | 
			
		||||
        u'zerver.userprofile': {
 | 
			
		||||
            'Meta': {'object_name': 'UserProfile'},
 | 
			
		||||
            'alert_words': ('django.db.models.fields.TextField', [], {'default': "'[]'"}),
 | 
			
		||||
            'api_key': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
 | 
			
		||||
            'autoscroll_forever': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'avatar_source': ('django.db.models.fields.CharField', [], {'default': "'G'", 'max_length': '1'}),
 | 
			
		||||
            'bot_owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.UserProfile']", 'null': 'True', 'on_delete': 'models.SET_NULL'}),
 | 
			
		||||
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
 | 
			
		||||
            'default_all_public_streams': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'default_desktop_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'default_events_register_stream': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': u"orm['zerver.Stream']"}),
 | 
			
		||||
            'default_sending_stream': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'null': 'True', 'to': u"orm['zerver.Stream']"}),
 | 
			
		||||
            'email': ('django.db.models.fields.EmailField', [], {'unique': 'True', 'max_length': '75', 'db_index': 'True'}),
 | 
			
		||||
            'enable_desktop_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'enable_digest_emails': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'enable_offline_email_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'enable_offline_push_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'enable_sounds': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'enable_stream_desktop_notifications': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'enable_stream_sounds': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'enter_sends': ('django.db.models.fields.NullBooleanField', [], {'default': 'True', 'null': 'True', 'blank': 'True'}),
 | 
			
		||||
            'full_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
 | 
			
		||||
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
 | 
			
		||||
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
 | 
			
		||||
            'invites_granted': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
 | 
			
		||||
            'invites_used': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
 | 
			
		||||
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
 | 
			
		||||
            'is_bot': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'is_mirror_dummy': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            '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_pointer_updater': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
 | 
			
		||||
            'last_reminder': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'null': 'True'}),
 | 
			
		||||
            'muted_topics': ('django.db.models.fields.TextField', [], {'default': "'[]'"}),
 | 
			
		||||
            'onboarding_steps': ('django.db.models.fields.TextField', [], {'default': "'[]'"}),
 | 
			
		||||
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
 | 
			
		||||
            'pointer': ('django.db.models.fields.IntegerField', [], {}),
 | 
			
		||||
            'rate_limits': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100'}),
 | 
			
		||||
            'realm': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['zerver.Realm']"}),
 | 
			
		||||
            'short_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
 | 
			
		||||
            'tutorial_status': ('django.db.models.fields.CharField', [], {'default': "'W'", 'max_length': '1'}),
 | 
			
		||||
            'twenty_four_hour_time': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
 | 
			
		||||
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"})
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    complete_apps = ['zerver']
 | 
			
		||||
@@ -328,6 +328,9 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
 | 
			
		||||
    enter_sends = models.NullBooleanField(default=True)
 | 
			
		||||
    autoscroll_forever = models.BooleanField(default=False)
 | 
			
		||||
 | 
			
		||||
    # display settings
 | 
			
		||||
    twenty_four_hour_time = models.BooleanField(default=False)
 | 
			
		||||
 | 
			
		||||
    # Hours to wait before sending another email to a user
 | 
			
		||||
    EMAIL_REMINDER_WAITPERIOD = 24
 | 
			
		||||
    # Minutes to wait before warning a bot owner that her bot sent a message
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,7 @@ from zerver.lib.actions import (
 | 
			
		||||
    do_set_realm_invite_by_admins_only,
 | 
			
		||||
    do_update_message,
 | 
			
		||||
    do_update_pointer,
 | 
			
		||||
    do_change_twenty_four_hour_time,
 | 
			
		||||
    fetch_initial_state_data,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -434,6 +435,21 @@ class EventsRegisterTest(AuthedTestCase):
 | 
			
		||||
            error = schema_checker('events[0]', events[0])
 | 
			
		||||
            self.assert_on_error(error)
 | 
			
		||||
 | 
			
		||||
    def test_change_twenty_four_hour_time(self):
 | 
			
		||||
        schema_checker = check_dict([
 | 
			
		||||
            ('type', equals('update_display_settings')),
 | 
			
		||||
            ('op', equals('update')),
 | 
			
		||||
            ('person', check_dict([
 | 
			
		||||
                ('email', check_string),
 | 
			
		||||
                ('twenty_four_hour_time', check_bool),
 | 
			
		||||
            ])),
 | 
			
		||||
        ])
 | 
			
		||||
        # The first False is probably a noop, then we get transitions in both directions.
 | 
			
		||||
        for twenty_four_hour_time in [False, True, False]:
 | 
			
		||||
            events = self.do_test(lambda: do_change_twenty_four_hour_time(self.user_profile, twenty_four_hour_time))
 | 
			
		||||
            error = schema_checker('events[0]', events[0])
 | 
			
		||||
            self.assert_on_error(error)
 | 
			
		||||
 | 
			
		||||
    def test_realm_emoji_events(self):
 | 
			
		||||
        schema_checker = check_dict([
 | 
			
		||||
            ('type', equals('realm_emoji')),
 | 
			
		||||
@@ -463,6 +479,7 @@ class EventsRegisterTest(AuthedTestCase):
 | 
			
		||||
        error = schema_checker('events[0]', events[0])
 | 
			
		||||
        self.assert_on_error(error)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def test_create_bot(self):
 | 
			
		||||
        bot_created_checker = check_dict([
 | 
			
		||||
            ('type', equals('realm_bot')),
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ from zerver.lib.actions import bulk_remove_subscriptions, do_change_password, \
 | 
			
		||||
    do_change_enable_stream_desktop_notifications, do_change_enable_stream_sounds, \
 | 
			
		||||
    do_change_stream_description, do_get_streams, do_make_stream_private, \
 | 
			
		||||
    do_regenerate_api_key, do_remove_default_stream, do_update_pointer, \
 | 
			
		||||
    do_change_avatar_source
 | 
			
		||||
    do_change_avatar_source, do_change_twenty_four_hour_time
 | 
			
		||||
 | 
			
		||||
from zerver.lib.create_user import random_api_key
 | 
			
		||||
from zerver.lib.push_notifications import num_push_devices_for_user
 | 
			
		||||
@@ -1071,6 +1071,7 @@ def home(request):
 | 
			
		||||
            user_profile.enable_offline_email_notifications,
 | 
			
		||||
        enable_offline_push_notifications =
 | 
			
		||||
            user_profile.enable_offline_push_notifications,
 | 
			
		||||
        twenty_four_hour_time = register_ret['twenty_four_hour_time'],
 | 
			
		||||
 | 
			
		||||
        enable_digest_emails  = user_profile.enable_digest_emails,
 | 
			
		||||
        event_queue_id        = register_ret['queue_id'],
 | 
			
		||||
@@ -1710,6 +1711,18 @@ def json_change_settings(request, user_profile,
 | 
			
		||||
 | 
			
		||||
    return json_success(result)
 | 
			
		||||
 | 
			
		||||
@authenticated_json_post_view
 | 
			
		||||
@has_request_variables
 | 
			
		||||
def json_time_setting(request, user_profile, twenty_four_hour_time=REQ(validator=check_bool,default=None)):
 | 
			
		||||
    result = {}
 | 
			
		||||
    if twenty_four_hour_time is not None and \
 | 
			
		||||
        user_profile.twenty_four_hour_time != twenty_four_hour_time:
 | 
			
		||||
        do_change_twenty_four_hour_time(user_profile, twenty_four_hour_time)
 | 
			
		||||
 | 
			
		||||
    result['twenty_four_hour_time'] = twenty_four_hour_time
 | 
			
		||||
 | 
			
		||||
    return json_success(result)
 | 
			
		||||
 | 
			
		||||
@authenticated_json_post_view
 | 
			
		||||
@has_request_variables
 | 
			
		||||
def json_change_notify_settings(request, user_profile,
 | 
			
		||||
 
 | 
			
		||||
@@ -145,6 +145,7 @@ urlpatterns += patterns('zerver.views',
 | 
			
		||||
    url(r'^json/set_alert_words$',          'json_set_alert_words'),
 | 
			
		||||
    url(r'^json/set_muted_topics$',         'json_set_muted_topics'),
 | 
			
		||||
    url(r'^json/set_avatar$',               'json_set_avatar'),
 | 
			
		||||
    url(r'^json/time_setting$',             'json_time_setting'),
 | 
			
		||||
 | 
			
		||||
    # This json format view is used by the LEGACY pre-REST API.  It
 | 
			
		||||
    # requires an API key.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user