mirror of
https://github.com/zulip/zulip.git
synced 2025-11-09 16:37:23 +00:00
committed by
Tim Abbott
parent
1e948ab405
commit
e82c879b85
@@ -89,6 +89,8 @@ exports.add_custom_profile_fields_to_settings = function () {
|
|||||||
type = "date";
|
type = "date";
|
||||||
} else if (field_type === "URL") {
|
} else if (field_type === "URL") {
|
||||||
type = "url";
|
type = "url";
|
||||||
|
} else if (field_type === "User") {
|
||||||
|
type = "user";
|
||||||
} else {
|
} else {
|
||||||
blueslip.error("Undefined field type.");
|
blueslip.error("Undefined field type.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,15 @@ ViewFuncT = TypeVar('ViewFuncT', bound=Callable[..., HttpResponse])
|
|||||||
# including many examples
|
# including many examples
|
||||||
Validator = Callable[[str, object], Optional[str]]
|
Validator = Callable[[str, object], Optional[str]]
|
||||||
ExtendedValidator = Callable[[str, str, object], Optional[str]]
|
ExtendedValidator = Callable[[str, str, object], Optional[str]]
|
||||||
|
RealmUserValidator = Callable[[int, object, bool], Optional[str]]
|
||||||
|
|
||||||
ProfileDataElement = Dict[str, Union[int, float, Optional[str]]]
|
ProfileDataElement = Dict[str, Union[int, float, Optional[str]]]
|
||||||
ProfileData = List[ProfileDataElement]
|
ProfileData = List[ProfileDataElement]
|
||||||
|
|
||||||
FieldElement = Tuple[int, str, Validator, Callable[[Any], Any]]
|
FieldElement = Tuple[int, str, Validator, Callable[[Any], Any]]
|
||||||
ExtendedFieldElement = Tuple[int, str, ExtendedValidator, Callable[[Any], Any]]
|
ExtendedFieldElement = Tuple[int, str, ExtendedValidator, Callable[[Any], Any]]
|
||||||
|
UserFieldElement = Tuple[int, str, RealmUserValidator, Callable[[Any], Any]]
|
||||||
|
|
||||||
FieldTypeData = List[Union[FieldElement, ExtendedFieldElement]]
|
FieldTypeData = List[Union[FieldElement, ExtendedFieldElement, UserFieldElement]]
|
||||||
|
|
||||||
ProfileFieldData = Dict[str, Dict[str, str]]
|
ProfileFieldData = Dict[str, Dict[str, str]]
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.11 on 2018-05-08 17:24
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('zerver', '0171_userprofile_dense_mode'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='customprofilefield',
|
||||||
|
name='field_type',
|
||||||
|
field=models.PositiveSmallIntegerField(choices=[(1, 'Short text'), (2, 'Long text'), (4, 'Date'), (5, 'URL'), (3, 'Choice'), (6, 'User')], default=1),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -36,7 +36,8 @@ from zerver.lib.validator import check_int, check_float, \
|
|||||||
check_url
|
check_url
|
||||||
from zerver.lib.name_restrictions import is_disposable_domain
|
from zerver.lib.name_restrictions import is_disposable_domain
|
||||||
from zerver.lib.types import Validator, ExtendedValidator, \
|
from zerver.lib.types import Validator, ExtendedValidator, \
|
||||||
ProfileDataElement, ProfileData, FieldTypeData
|
ProfileDataElement, ProfileData, FieldTypeData, FieldElement, \
|
||||||
|
RealmUserValidator
|
||||||
|
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
@@ -1971,16 +1972,24 @@ class CustomProfileField(models.Model):
|
|||||||
CHOICE = 3
|
CHOICE = 3
|
||||||
DATE = 4
|
DATE = 4
|
||||||
URL = 5
|
URL = 5
|
||||||
|
USER = 6
|
||||||
|
|
||||||
# These are the fields whose validators require field_data
|
# These are the fields whose validators require more than var_name
|
||||||
# argument as well.
|
# and value argument. i.e. CHOICE require field_data, USER require
|
||||||
EXTENDED_FIELD_TYPE_DATA = [
|
# realm as argument.
|
||||||
|
CHOICE_FIELD_TYPE_DATA = [
|
||||||
(CHOICE, str(_('Choice')), validate_choice_field, str),
|
(CHOICE, str(_('Choice')), validate_choice_field, str),
|
||||||
] # type: FieldTypeData
|
] # type: FieldTypeData
|
||||||
|
USER_FIELD_TYPE_DATA = [
|
||||||
|
(USER, str(_('User')), check_valid_user_id, int),
|
||||||
|
] # type: FieldTypeData
|
||||||
|
|
||||||
EXTENDED_FIELD_VALIDATORS = {
|
CHOICE_FIELD_VALIDATORS = {
|
||||||
item[0]: item[2] for item in EXTENDED_FIELD_TYPE_DATA
|
item[0]: item[2] for item in CHOICE_FIELD_TYPE_DATA
|
||||||
} # type: Dict[int, ExtendedValidator]
|
} # type: Dict[int, ExtendedValidator]
|
||||||
|
USER_FIELD_VALIDATORS = {
|
||||||
|
item[0]: item[2] for item in USER_FIELD_TYPE_DATA
|
||||||
|
} # type: Dict[int, RealmUserValidator]
|
||||||
|
|
||||||
FIELD_TYPE_DATA = [
|
FIELD_TYPE_DATA = [
|
||||||
# Type, Name, Validator, Converter
|
# Type, Name, Validator, Converter
|
||||||
@@ -1990,7 +1999,7 @@ class CustomProfileField(models.Model):
|
|||||||
(URL, str(_('URL')), check_url, str),
|
(URL, str(_('URL')), check_url, str),
|
||||||
] # type: FieldTypeData
|
] # type: FieldTypeData
|
||||||
|
|
||||||
ALL_FIELD_TYPES = FIELD_TYPE_DATA + EXTENDED_FIELD_TYPE_DATA
|
ALL_FIELD_TYPES = FIELD_TYPE_DATA + CHOICE_FIELD_TYPE_DATA + USER_FIELD_TYPE_DATA
|
||||||
|
|
||||||
FIELD_VALIDATORS = {item[0]: item[2] for item in FIELD_TYPE_DATA} # type: Dict[int, Validator]
|
FIELD_VALIDATORS = {item[0]: item[2] for item in FIELD_TYPE_DATA} # type: Dict[int, Validator]
|
||||||
FIELD_CONVERTERS = {item[0]: item[3] for item in ALL_FIELD_TYPES} # type: Dict[int, Callable[[Any], Any]]
|
FIELD_CONVERTERS = {item[0]: item[3] for item in ALL_FIELD_TYPES} # type: Dict[int, Callable[[Any], Any]]
|
||||||
|
|||||||
@@ -342,6 +342,21 @@ class CustomProfileFieldTest(ZulipTestCase):
|
|||||||
self.assert_error_update_invalid_value(field_name, u"not URL",
|
self.assert_error_update_invalid_value(field_name, u"not URL",
|
||||||
u"{} is not a URL".format(field_name))
|
u"{} is not a URL".format(field_name))
|
||||||
|
|
||||||
|
def test_update_invalid_user_field(self) -> None:
|
||||||
|
field_name = "Mentor"
|
||||||
|
invalid_user_id = 1000
|
||||||
|
self.assert_error_update_invalid_value(field_name, invalid_user_id,
|
||||||
|
u"Invalid user ID: %d"
|
||||||
|
% (invalid_user_id))
|
||||||
|
|
||||||
|
def test_create_field_of_type_user(self) -> None:
|
||||||
|
self.login(self.example_email("iago"))
|
||||||
|
data = {"name": "Your mentor",
|
||||||
|
"field_type": CustomProfileField.USER,
|
||||||
|
}
|
||||||
|
result = self.client_post("/json/realm/profile_fields", info=data)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
def test_update_profile_data_successfully(self) -> None:
|
def test_update_profile_data_successfully(self) -> None:
|
||||||
self.login(self.example_email("iago"))
|
self.login(self.example_email("iago"))
|
||||||
realm = get_realm('zulip')
|
realm = get_realm('zulip')
|
||||||
@@ -352,6 +367,7 @@ class CustomProfileFieldTest(ZulipTestCase):
|
|||||||
('Favorite editor', 'vim'),
|
('Favorite editor', 'vim'),
|
||||||
('Birthday', '1909-3-5'),
|
('Birthday', '1909-3-5'),
|
||||||
('GitHub profile', 'https://github.com/ABC'),
|
('GitHub profile', 'https://github.com/ABC'),
|
||||||
|
('Mentor', self.example_user("cordelia").id),
|
||||||
]
|
]
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
|||||||
@@ -131,18 +131,21 @@ def update_user_custom_profile_data(
|
|||||||
return json_error(_('Field id {id} not found.').format(id=field_id))
|
return json_error(_('Field id {id} not found.').format(id=field_id))
|
||||||
|
|
||||||
validators = CustomProfileField.FIELD_VALIDATORS
|
validators = CustomProfileField.FIELD_VALIDATORS
|
||||||
extended_validators = CustomProfileField.EXTENDED_FIELD_VALIDATORS
|
|
||||||
field_type = field.field_type
|
field_type = field.field_type
|
||||||
value = item['value']
|
value = item['value']
|
||||||
var_name = '{}'.format(field.name)
|
var_name = '{}'.format(field.name)
|
||||||
if field_type in validators:
|
if field_type in validators:
|
||||||
validator = validators[field_type]
|
validator = validators[field_type]
|
||||||
result = validator(var_name, value)
|
result = validator(var_name, value)
|
||||||
else:
|
elif field_type == CustomProfileField.CHOICE:
|
||||||
# Check extended validators.
|
choice_field_validator = CustomProfileField.CHOICE_FIELD_VALIDATORS[field_type]
|
||||||
extended_validator = extended_validators[field_type]
|
|
||||||
field_data = field.field_data
|
field_data = field.field_data
|
||||||
result = extended_validator(var_name, field_data, value)
|
result = choice_field_validator(var_name, field_data, value)
|
||||||
|
elif field_type == CustomProfileField.USER:
|
||||||
|
user_field_validator = CustomProfileField.USER_FIELD_VALIDATORS[field_type]
|
||||||
|
result = user_field_validator(user_profile.realm.id, value, False)
|
||||||
|
else:
|
||||||
|
raise AssertionError("Invalid field type")
|
||||||
|
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return json_error(result)
|
return json_error(result)
|
||||||
|
|||||||
@@ -327,6 +327,8 @@ class Command(BaseCommand):
|
|||||||
favorite_website = try_add_realm_custom_profile_field(zulip_realm, "GitHub profile",
|
favorite_website = try_add_realm_custom_profile_field(zulip_realm, "GitHub profile",
|
||||||
CustomProfileField.URL,
|
CustomProfileField.URL,
|
||||||
hint="Or your personal blog's URL")
|
hint="Or your personal blog's URL")
|
||||||
|
mentor = try_add_realm_custom_profile_field(zulip_realm, "Mentor",
|
||||||
|
CustomProfileField.USER)
|
||||||
|
|
||||||
# Fill in values for Iago and Hamlet
|
# Fill in values for Iago and Hamlet
|
||||||
hamlet = get_user("hamlet@zulip.com", zulip_realm)
|
hamlet = get_user("hamlet@zulip.com", zulip_realm)
|
||||||
@@ -337,6 +339,7 @@ class Command(BaseCommand):
|
|||||||
{"id": favorite_editor.id, "value": "emacs"},
|
{"id": favorite_editor.id, "value": "emacs"},
|
||||||
{"id": birthday.id, "value": "2000-1-1"},
|
{"id": birthday.id, "value": "2000-1-1"},
|
||||||
{"id": favorite_website.id, "value": "https://github.com/zulip/zulip"},
|
{"id": favorite_website.id, "value": "https://github.com/zulip/zulip"},
|
||||||
|
{"id": mentor.id, "value": hamlet.id},
|
||||||
])
|
])
|
||||||
do_update_user_custom_profile_data(hamlet, [
|
do_update_user_custom_profile_data(hamlet, [
|
||||||
{"id": phone_number.id, "value": "+0-11-23-456-7890"},
|
{"id": phone_number.id, "value": "+0-11-23-456-7890"},
|
||||||
@@ -345,6 +348,7 @@ class Command(BaseCommand):
|
|||||||
{"id": favorite_editor.id, "value": "vim"},
|
{"id": favorite_editor.id, "value": "vim"},
|
||||||
{"id": birthday.id, "value": "1900-1-1"},
|
{"id": birthday.id, "value": "1900-1-1"},
|
||||||
{"id": favorite_website.id, "value": "https://blog.zulig.org"},
|
{"id": favorite_website.id, "value": "https://blog.zulig.org"},
|
||||||
|
{"id": mentor.id, "value": iago.id},
|
||||||
])
|
])
|
||||||
else:
|
else:
|
||||||
zulip_realm = get_realm("zulip")
|
zulip_realm = get_realm("zulip")
|
||||||
|
|||||||
Reference in New Issue
Block a user