fusionbox / django-authtools Goto Github PK
View Code? Open in Web Editor NEWA custom User model for everybody!
Home Page: https://django-authtools.readthedocs.org/
License: BSD 2-Clause "Simplified" License
A custom User model for everybody!
Home Page: https://django-authtools.readthedocs.org/
License: BSD 2-Clause "Simplified" License
I noticed that AbstractEmailUser does not reproduce the .clean()
method that Django's AbstractUser provides, which means normalize_email()
(lowercasify the domain portion) is not being invoked on save.
https://github.com/django/django/blob/master/django/contrib/auth/models.py#L363-L365:
def clean(self):
super().clean()
self.email = self.__class__.objects.normalize_email(self.email)
I would assume that this is deliberate, but authtools' implementation of UserManager.create_user()
does include normalize_email()
https://github.com/fusionbox/django-authtools/blob/master/authtools/models.py#L12-L17
def create_user(self, email, password=None, **kwargs):
email = self.normalize_email(email)
// ...
Which means that users created with manage.py createsuperuser
will have their emails normalized, but users created through the Django Admin will not.
I would like to draw your attention to this ticket and this discussion.
Hi there!
The CBV WithNextUrlMixin currently generates the following warnings:
RemovedInDjango19Warning: `request.REQUEST` is deprecated, use `request.GET` or `request.POST` instead.
if self.redirect_field_name in self.request.REQUEST:
RemovedInDjango19Warning: `request.REQUEST` is deprecated, use `request.GET` or `request.POST` instead.
redirect_to = self.request.REQUEST[self.redirect_field_name]
It's not a major concern at the moment, but I thought I'd contribute this re-write:
def get_next_url(self):
# if self.redirect_field_name in self.request.REQUEST:
# redirect_to = self.request.REQUEST[self.redirect_field_name]
# if is_safe_url(redirect_to, host=self.request.get_host()):
# return redirect_to
redirect_to = self.request.POST.get(self.redirect_field_name,
self.request.GET.get(self.redirect_field_name, ''))
if is_safe_url(redirect_to, host=self.request.get_host()):
return redirect_to
I'm leaving the old code commented above, so that you can easily compare the change.
Thanks for all the hard work. ;-)
is it supported? i can't find anything in documentation
For some reason pkg_resources
can not find the version of the lib authtools
and generates the error below:
mod_wsgi (pid=12640): Target WSGI script '...\\wsgi.py' cannot be loaded as Python module.
mod_wsgi (pid=12640): Exception occurred processing WSGI script '...\\wsgi.py'.
Traceback (most recent call last):
File "...\\wsgi.py", line 48, in <module>
_application = get_wsgi_application()
File "...\\django\\core\\wsgi.py", line 14, in get_wsgi_application
django.setup()
File "...\\django\\__init__.py", line 21, in setup
apps.populate(settings.INSTALLED_APPS)
File "...\\django\\apps\\registry.py", line 115, in populate
app_config.ready()
File "...\\xadmin\\apps.py", line 13, in ready
self.module.autodiscover()
File "...\\xadmin\\__init__.py", line 55, in autodiscover
import_module('%s.adminx' % app)
File "...\django\\utils\\importlib.py", line 46, in import_module
__import__(name)
File "...\\app\\adminx.py", line 4, in <module>
from authtools.forms import UserCreationForm, AdminUserChangeForm
File "...\\pyenv\\Lib\\site-packages\\authtools\\__init__.py", line 3, in <module>
__version__ = pkg_resources.get_distribution('django-authtools').version
File "...\\pkg_resources\\__init__.py", line 539, in get_distribution
dist = get_provider(dist)
File "...\\pkg_resources\\__init__.py", line 419, in get_provider
File "...\\pkg_resources\\__init__.py", line 940, in require
needed = self.resolve(parse_requirements(requirements))
File "...\\pkg_resources\\__init__.py", line 827, in resolve
raise DistributionNotFound(req, requirers)
DistributionNotFound: The 'django-authtools' distribution was not found and is required by the application
If the comment line below the error disappears (authtools.init):
pkg_resources.get_distribution('django-authtools').version
See my environment is to:
Python 2.7.9
Django 1.7
Xadmin (branch django 1.7)
Apache2 (with wsgi)
django-authtools
- It is installed in a virtual environment (created with virtualenv).
Hi,
Could we please also pass in request=self.request
here to meet the requirements for django-axes
authentication back-end?
django-authtools/authtools/views.py
Line 380 in 74954bc
When I try to use the function as described above I get the following error:
http://dpaste.com/1T5KG1M
It seems that when request is added to save it works: http://stackoverflow.com/questions/23591192/django-custom-passwordresetform
reset_form.save(
subject_template_name='registration/password_reset_subject.txt',
email_template_name='registration/password_reset_email.html',
request=request
)
The user password change link no longer works in Django 2.0.2. The help text needs to be formatted to insert the URL.
Hi, i'm trying since a couple of days to install the package via pip3 in a venv in my "test" machine powered by archlinux.
I get this error msg:
(py3env) [kaddour@archlinux edge]$ pip3 install django-authtools
Collecting django-authtools
Using cached django-authtools-1.2.0.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 20, in <module>
File "/tmp/pip-build-m5e6ar3z/django-authtools/setup.py", line 23, in <module>
long_description='\n\n'.join([read('README.rst'), read('CHANGES.rst')]),
File "/tmp/pip-build-m5e6ar3z/django-authtools/setup.py", line 10, in read
return open(os.path.join(os.path.dirname(__file__), fname)).read()
File "/usr/lib/python3.4/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 721: ordinal not in range(128)
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-m5e6ar3z/django-authtools
I believe it has to do with encoding, using ascii
instead of utf8
Any help is welcome !
I'm running into an issue where {% url 'password_reset' %}
is returning the wrong url because another app in my project has registered an url with that name. And I can't just move that other app (mezzanine) up before authtools in urls.py
because Mezzanine includes a catch all url so it should come last.
So wouldn't it be a good idea in all cases to use a namespace so one could use authtools:password_reset
instead?
Hey folks,
Just wondering what your contributors landscape looks like. I'm going to be using this library in a production environment and want to give back - let me know what can help.
Thanks
This was going to be a PR, until I discovered that most of django.contrib.auth.tests
(which the authtools suite imports) was moved out of the django namespace in Django 1.8.x. I presume this is why Django 1.8 isn't already included in Tox/Travis.
Possible options:
vendor/django_1_8/tests/auth_tests
directory (possibly as a git submodule) and import from there when testing Django 1.8Thoughts?
When trying to use the link in the django user admin to change a user's password, I get a 404.
Clicking the link on the page: "Raw passwords are not stored, so there is no way to see this user's password, but you can change the password using this form", should link to /admin/accounts/user/{pk}/password/
, but it is instead linking to /admin/accounts/user/password/
https://pypi.python.org/pypi/django-authtools/1.1.0
I think it's the sphinx-specific RST commands in the Changelog.
It needs to call django.contrib.auth.password_validation.validate_password to hook in to https://docs.djangoproject.com/en/dev/topics/auth/passwords/#enabling-password-validation
There seems to have been a regression with issue #62 and #64 using Django==1.10.3
and django-authtools==1.5.0
As a workaround i did this custom form (without the translation _
):
from django.contrib.auth.forms import UserChangeForm as DjangoUserChangeForm
from authtools.forms import UserChangeForm
class CustomAdminUserChangeForm(UserChangeForm):
def __init__(self, *args, **kwargs):
super(CustomAdminUserChangeForm, self).__init__(*args, **kwargs)
if not self.fields['password'].help_text:
self.fields['password'].help_text = (
"Raw passwords are not stored, so there is no way to see this"
" user's password, but you can change the password using"
" <a href=\"../password/\">this form</a>.")
Postgres performs string comparison case-sensitively, mysql does it case-insensitive. This means that on postgres, [email protected]
, [email protected]
and [email protected]
are all distinct emails, and a user could register with each one.
Domain names are not case sensitive, so at least the domain part should lowercased. The local part of an email address is technically case sensitive, but I don't think it is in practice.
The easiest way to accomplish this would be to lowercase email addresses before storing them, but it might be wrong to mangle addresses like that.
It seems the authtools module is not recognized when deploying the application in AWS EC2 (unless I am doing something wrong which is quite likely). I have posted the issue on SO (https://stackoverflow.com/questions/44902540/cannot-overwrite-django-authentication-templates-in-aws), I would appreciate a sanity check from someone to understand if there is an issue with the module itself and it's compatibility with the Django/Python version deployed by AWS or if I am missing something.
Thanks
1.7 added the ability to have the session authenticated by a hash of user details; see here:
https://github.com/django/django/pull/2494/files#diff-7
I think PasswordChangeView's form_valid
could do with a call to update_session_auth_hash
to ensure changing the password doesn't log the user out before they even get to the PasswordChangeDoneView.
For now, the following workaround seem to suffice:
class CustomPasswordChangeView(PasswordChangeView):
def form_valid(self, form):
result = super(CustomPasswordChangeView, self).form_valid(form)
update_session_auth_hash(self.request, form.user)
return result
I'm getting a missing migration warning on 1.8 with authtools:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('authtools', '0002_django18'),
]
operations = [
migrations.AlterField(
model_name='user',
name='groups',
field=models.ManyToManyField(related_query_name='user', related_name='user_set', to='auth.Group', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', verbose_name='groups'),
),
]
I just wrote my own PasswordChangeForm/PasswordChangeView in one of my project. (The form is two password fields, and ask for the current password). I also created EmailChangeForm/EmailChangeView (with newemail/password confirmation)
IMHO, it sounds like something that should go in authtools. What do you think?
FYI, It looks like this:
class UpdatePasswordForm(forms.Form):
password1 = forms.CharField(label='New password',
widget=forms.PasswordInput)
password2 = forms.CharField(
label='Password confirmation',
help_text='Same password as above.',
widget=forms.PasswordInput,
)
current = forms.CharField(label='Current password',
widget=forms.PasswordInput)
def __init__(self, *args, **kwargs):
self.instance = kwargs.pop('instance', None)
assert self.instance is not None
super(UpdatePasswordForm, self).__init__(*args, **kwargs)
def clean_current(self):
password = self.cleaned_data['current']
assert self.instance is not None
if not self.instance.check_password(password):
raise forms.ValidationError("The current password was invalid.")
return password
def clean(self):
cleaned_data = super(UpdatePasswordForm, self).clean()
if cleaned_data['password1'] != cleaned_data['password2']:
raise forms.ValidationError("Passwords didn't match")
return cleaned_data
def save(self, commit=True):
assert self.instance is not None
self.instance.set_password(self.cleaned_data['password1'])
if commit:
self.instance.save()
return self.instance
class UpdatePasswordView(EnsureAuthMixin, UpdateView):
form_class = UpdatePasswordForm
template_name = 'auth/update_password.html'
def get_object(self):
user = self.request.user
assert not user.is_anonymous()
return user
I've implemented the admin.py as described in 'http://django-authtools.readthedocs.org/en/latest/how-to/invitation-email.html'
When I leave the password fields open a password is still generated?. So obj.has_usable_password() is set to True. So no email is send.
In this tutorial: https://django-authtools.readthedocs.io/en/latest/how-to/migrate-to-a-custom-user-model.html
It says:
$ python manage.py schemamigration --initial accounts
According to my research this command was from the now depreciated South
, and does not exist anymore. Please suggest a work around.
We need a place to host some good default templates for the log in stuff. We can provide some, but it's going to be hard to support everybody's block structures, so they might just serve as examples.
I think it might be possible to make these templates work for maybe a quarter of people if they extend from base.html
and then only put stuff in block content
, but they will never be a universal solution.
I want users to signin with either username or email address. I did not see anything in documentation regarding this. Is this possible with django-authtools ?
See this comment in the Django 1.10 release notes re: "AbstractUser.username max_length increased to 150":
We considered an increase to 254 characters to more easily allow the use of email addresses (which are limited to 254 characters) as usernames but rejected it due to a MySQL limitation. When using the utf8mb4 encoding (recommended for proper Unicode support), MySQL can only create unique indexes with 191 characters by default.
Authtools' 255 character email field walks into exactly that problem.
I doubt you'll want to change max_length
just to satisfy MySQL, so two thoughts.
First, you could make max_length
configurable via settings, with a default of 255?
Second, you could document the problem and the workaround? The workaround is straightforward:
class User(authtools.models.AbstractNamedUser):
email = django.db.models.EmailField(
_('email address'), max_length=190, unique=True)
Of course, you also have to point AUTH_USER_MODEL
to that class, and register the class in the admin using something like:
admin.site.register(User, authtools.admin.NamedUserAdmin)
I am trying to write a pytest test of one of my views that requires a logged-in admin user and I'm using the pytest-django admin_client
fixture for that.
This fails as follows:
try:
user = UserModel._default_manager.get(**{username_field: username})
except UserModel.DoesNotExist:
extra_fields = {}
if username_field not in ("username", "email"):
extra_fields[username_field] = "admin"
user = UserModel._default_manager.create_superuser(
> username, "[email protected]", "password", **extra_fields
)
E TypeError: create_superuser() takes 1 positional argument but 4 were given
../.virtualenvs/test3/lib/python3.7/site-packages/pytest_django/fixtures.py:298: TypeError
I investigated and it's because authtools defines create_superuser
like this:
def create_superuser(self, **kwargs):
using only one positional argument (self
). The pytest-django fixture tries to invoke the function like Django expects up until 3.0, using username, email and password. In 3.0 only username is required so this problem might be solved but I'm on 2.2 and you seem to support 1.11 and maybe earlier too.
So is this a bug? I can work around it for now but thought I'd notify you. And thanks for a great package btw
Looks as though django.utils.encoding.python_2_unicode_compatible()
has been removed from Django which this library makes use of. It was just an alias to six anyway.
To install from source I had to use:
pip install -e git+http://github.com/fusionbox/django-authtools@master#egg=django-authtools-dev
instead of:
pip install -e git://github.com/fusionbox/django-authtools@master#egg=django-authtools-dev
https://django-authtools.readthedocs.org/en/latest/intro.html#installation
https://github.com/fusionbox/django-authtools/blob/master/authtools/models.py#L29-L30
Hi
Is there any sense to use both at the same time?
It seemed to me that in this case, a unique index is enough
There is a potential permission escalation issue with the out-of-the-box configuration of authtools.
Users who are is_staff
and have permissions to see the User section can currently edit their own permissions and also edit the passwords of superusers.
I did some work in one of my projects to prevent this, but I don't think it's possible to make this generic.
def get_fieldsets(self, request, obj=None):
if not obj or request.user.is_superuser:
return super(UserAdmin, self).get_fieldsets(request, obj)
# permission escalation avoidance. Staff can change each others'
# passwords, but not edit permissions or change superusers' passwords.
base_fields = copy.deepcopy(BASE_FIELDS)
if obj and obj.is_superuser:
base_fields[1]['fields'] = REQUIRED_FIELDS
return (base_fields,) + self.declared_fieldsets[2:]
There is still the possibility that an is_staff User gains more permissions by changing the password of other is_staff
ers, but they still won't be able to gain superuser access.
All this being said, I think the best we can do is just to put some warnings in the docs. Thoughts?
Following the docs on "How To Create Users Without Setting Their Password" https://django-authtools.readthedocs.io/en/latest/how-to/invitation-email.html (relevant code snippet below), the call to reset_form.save
could trigger SMTPRecipientsRefused
if the recipient email address is invalid, currently it will result in a 500 as-is. My understanding is that usually form error validations are handled in the clean_*
method, any suggestions on how to deal with the SMTPRecipientsRefused
exception in this case?
def save_model(self, request, obj, form, change):
if not change and (not form.cleaned_data['password1'] or not obj.has_usable_password()):
# Django's PasswordResetForm won't let us reset an unusable
# password. We set it above super() so we don't have to save twice.
obj.set_password(get_random_string())
reset_password = True
else:
reset_password = False
super(UserAdmin, self).save_model(request, obj, form, change)
if reset_password:
reset_form = PasswordResetForm({'email': obj.email})
assert reset_form.is_valid()
reset_form.save(
request=request,
use_https=request.is_secure(),
subject_template_name='registration/account_creation_subject.txt',
email_template_name='registration/account_creation_email.html',
)
A third migration gets created on django 1.8. Need to either add that migration to authtools, or fix the initial migration so the extra migration is not created. The reason the migration is created is because the help_text
on User.groups
"changed".
In the initial migration it is:
'The groups this user belongs to. A user will get all permissions granted to each of their groups'
But on the User model it is actually:
'The groups this user belongs to. A user will get all permissions granted to each of their groups.'
(just missing a period on the end)
The CaseInsensitiveEmailUserCreationForm
would be nice, but it only works if the USERNAME_FIELD
is 'username'
, so it does not work for email users. Which is odd because that is the type of user it says it works for in the name of the form class itself.
It doesn't do anything because clean_username
is hardcoded. It should really be clean_{USERNAME_FIELD}
I've created a new db for my Django 1.8 app. doing ./manage migrate
throws this error:
...
Synchronizing apps without migrations:
Creating tables...
Creating table authtools_user
Running deferred SQL...
Traceback (most recent call last):
File "./manage.py", line 12, in <module>
execute_from_command_line(sys.argv)
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
utility.execute()
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 330, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/core/management/base.py", line 390, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/core/management/base.py", line 441, in execute
output = self.handle(*args, **options)
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 179, in handle
created_models = self.sync_apps(connection, executor.loader.unmigrated_apps)
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 317, in sync_apps
cursor.execute(statement)
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/db/utils.py", line 97, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/user/.venvs/py2.7/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 62, in execute
return self.cursor.execute(sql)
django.db.utils.ProgrammingError: relation "auth_group" does not exist
however, installing Django 1.7, migrating the app and then upgrading Django to 1.8 works fine.
Django 2.1 added view only permission. This break BetterReadOnlyPasswordHashWidget:
TypeError: 'NoneType' object is not a mapping
...
File "django/contrib/admin/helpers.py", line 210, in contents
return widget.render(field, value)
File "authtools/forms.py", line 35, in render
final_attrs = flatatt(self.build_attrs(attrs))
File "django/forms/widgets.py", line 239, in build_attrs
return {**base_attrs, **(extra_attrs or {})}
I think changing render's attrs=None
default value, or add or {}
to build_attrs would probably fix this.
The manager defined over at https://github.com/fusionbox/django-authtools/blob/master/authtools/models.py#L12 does not seem to take the uniqueness properties of the model into account, I can see that about the same sort of code is used within django.contrib.auth but does that make sense? If I wanted to create a user using those "factory" like methods I could run into Integrity errors.
The code seems to work as far as I can tell.
null value in column "last_login" violates not-null constraint
may be related to this backwards incompatible change
When adding a new user and using the 'How To Create Users Without Setting Their Password' UserAdmin I suddenly get an error:
NOT NULL constraint failed: authtools_user.last_login
I've tried to find the problem but it should work on Django 1.8:
django/django@a2479f4
User inherits from AbstractBaseUser so last_login can be blank and null.
traceback: http://dpaste.com/16DTPRJ
Any ideas? It worked before..
I have found that the AuthenticationForm
does not have the request prop available to send through to authentication back-ends here https://github.com/django/django/blob/06909fe084f87a65459a83bd69d7cdbe4fce9a7c/django/contrib/auth/forms.py#L205 where it calls authenticate(self.request
the value of self.request
will always be None
This means that I am unable to make use of django-axes
authentication back-end that requires this value to be set.
Below I have tried my best to track the flow of logic:
LoginView
uses AuthenticationForm
https://github.com/fusionbox/django-authtools/blob/master/authtools/views.py#L153dispatch
is called django-authtools/authtools/views.py
Line 174 in 879d12b
dispatch
method here https://github.com/django/django/blob/06909fe084f87a65459a83bd69d7cdbe4fce9a7c/django/views/generic/base.py#L89ProcessFormView
https://github.com/django/django/blob/06909fe084f87a65459a83bd69d7cdbe4fce9a7c/django/views/generic/edit.py#L142form.is_valid()
is called from the form fetched here https://github.com/django/django/blob/06909fe084f87a65459a83bd69d7cdbe4fce9a7c/django/views/generic/edit.py#L33 which DOESN'T pass through the request propAuthenticationForm
's clean method calls authenticate
https://github.com/django/django/blob/06909fe084f87a65459a83bd69d7cdbe4fce9a7c/django/contrib/auth/forms.py#L205At this point it flows through the authentication back-ends and django-axes
throws an error due to request
being None
. Please help me to fix, or find a workaround.
Thank you
There is an error when passing allow_authenticated = False
. TypeError: 'bool' object is not callable
.
Per Django 2.0 release notes: "Using User.is_authenticated() and User.is_anonymous() as methods rather than properties is no longer supported."
When I try to use the reset email function to create an account I get a template not found error.
Shouldn't these be named like this?:
subject_template_name='registration/password_reset_subject.txt',
email_template_name='registration/password_reset_email.html',
http://django-authtools.readthedocs.org/en/latest/how-to/invitation-email.html
When I click on this form
in the route /admin/authtools/user/<id>/
the link redirects to /admin/authtools/user/password/
instead of /admin/authtools/user/<id>/password
.
Can we get a new stable release?
Creates migration in site-packages dependant on 0002_django18 when executing makemigrations
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2015-12-05 18:13
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authtools', '0002_django18'),
]
operations = [
migrations.AlterField(
model_name='user',
name='groups',
field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups'),
),
]
Thanks everyone for this app!
But I don't get how to write this email template (account_creation_email.html).
I read the manual: http://django-authtools.readthedocs.org/en/latest/how-to/invitation-email.html and I don't understand how to write email template to include password change link for the user. I just need simple example like:
some text
link to change password
I am really confused with that.
Hello!
I see where the Django 1.8 support got merged back in July, but a release has not been shipped to PyPi that includes it. v1.2
comes down with pip install django-authtools
, which doesn't function in 1.8.
It's not a problem to pin the install in requirements.txt
to the GitHub branch for now, but is there a plan to push that out soon?
Thanks!
I think there are different version source between git and pip.
I tried to install as next (in windwos)
$ pip install django-authtools
but it has different part within forms.py, views.py (AuthenticationForm)
Please, just check, if it is wrong.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.