thomasjohnkane / snooze Goto Github PK
View Code? Open in Web Editor NEWA package to simplify automating future notifications and reminders in Laravel
License: MIT License
A package to simplify automating future notifications and reminders in Laravel
License: MIT License
Hi. We used this good package at our stage server, at local version it is also works fine, but today we are added it to the production server (master branch is equal to stage branch) and got an error:
Type error: Argument 1 passed to Thomasjohnkane\Snooze\ScheduledNotification::create() must be an instance of Thomasjohnkane\Snooze\object,
instance of App\Models\VideoCall given, called in [...]/public/vendor/thomasjohnkane/snooze/src/Traits/SnoozeNotifiable.php on line 23
{"userId":40,"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Type error: Argument 1 passed
to Thomasjohnkane\\Snooze\\ScheduledNotification::create() must be an instance of Thomasjohnkane\\Snooze\\object,
instance of App\\Models\\VideoCall given, called in [...]/public/vendor/thomasjohnkane/snooze/src/Traits/SnoozeNotifiable.php
on line 23 at [...]/vendor/thomasjohnkane/snooze/src/ScheduledNotification.php:37)
[stacktrace]
#0 [...]/public/vendor/thomasjohnkane/snooze/src/Traits/SnoozeNotifiable.php(23):
Thomasjohnkane\\Snooze\\ScheduledNotification::create(Object(App\\Models\\VideoCall), Object(App\\Notifications\\VideoCallsNotice), Object(Carbon\\Carbon))
#1 [...]/public/app/Observers/VideoCallObserver.php(21):
App\\Models\\VideoCall->notifyAt(Object(App\\Notifications\\VideoCallsNotice), Object(Carbon\\Carbon))
#2 [internal function]: App\\Observers\\VideoCallObserver->created(Object(App\\Models\\VideoCall))
Our model VideoCall uses Notifiable and SnoozeNotifiable traits.
And we are calling it:
$call->notifyAt(new VideoCallsNotice(), $startDate->subMinutes(30));
Laravel 5.6
PHP 7.2.33
Maybe some PHP extension needs to be enabled, or something else?
I think we should add a way to cancel all future notifications for a target. For example, if they unsub we don't want to continue sending.
Possible implementation:
Add a target_type
column to the migration, and method to cancel outstanding notifications for a target.
Hi, thanks for this amazing package
in my local environment i used composer require thomasjohnkane/snooze
and php artisan migrate
which works perfectly fine and the local database migrated successfully
BUT
when i pushed updates to private git repo and then pull them in prod server
but i used composer install --no-scripts --no-dev
commend to install the package then
when i tried php artisan migrate
i get Nothing to migrate. message
Workaround
that i'm using right now is copying the migration file from snooze/migrations/2019_02_25_231036_create_scheduled_notifications_table.php
to the local env under database/migrations
folder than pushing changes to prod env than running php artisan migrate
I think we are ready to tag the first version of the package.
Is there anything else we need to do before then?
it's possible to preview scheduled notifications?
i.e. in Laravel 8 I can do something like to preview notifications:
Route::get('/preview', function () {
$admin = User::find(1);
$company = Company::find(1);
return (new CompanyRegistration($company))->toMail($admin);
});
I.e. its possible to do something like...:
$notification = ScheduledNotification::find(1);
return $notification->getPreview();
?
thnks
This way when Relation::morphMap is used
The entry in the database table is users instead of App\User
See:
https://laravel.com/docs/6.x/eloquent-relationships#custom-polymorphic-types
https://josephsilber.com/posts/2018/07/02/eloquent-polymorphic-relations-morph-map
Hi!
I tried use your package but I can't understand how use this in controllers. Please public more examples for controllers. Thank you!
Very great package i would say!
This is not really an issue, but rather a question of my curiosity. May i know, how you check the notification entries in table is due, let say when after running snooze:send
command?
Appreciate for the clarification!
Thanks
I'm creating a zip in AWS that might take as long as 15m. I'd like to send the notification as soon as possible, so ideally I'd check every minute, and then if it's ready I send the notification, if not, I reschedule.
I've done this by extending the custom model and overwriting the send method.
public function send(): void
{
// ...
if ($this->shouldInterrupt($notification, $notifiable)) {
$this->cancel();
event(new NotificationInterrupted($this));
return;
}
if($sendAt = $this->shouldRescheduleFor($notification, $notifiable)) {
$this->reschedule($sendAt);
return;
}
// ...
}
public function shouldRescheduleFor(?object $notification = null, ?object $notifiable = null):
\DateTimeInterface|string|null
{
if (! $notification) {
$notification = $this->serializer->unserialize($this->notification);
}
if (! $notifiable) {
$notifiable = $this->serializer->unserialize($this->target);
}
if (method_exists($notification, 'shouldRescheduleFor')) {
return $notification->shouldRescheduleFor($notifiable);
}
return null;
}
Created the issue mainly to ask if you think this might be a useful feature for the package. If that's the case, I can create a PR for this.
Thanks for the package! :)
I think it'd be a good idea to have an event or notification in the case that we have a large backlog of unsent notifications (snooze was not running for x days).
Otherwise it could just go unnoticed by the developer unless they checked the table.
Also, adding a command to cancel one that were missed (or doing this when the above notification is sent?)
I have a case when I've created a listener when notification is sent on laravel that have a simple task which is check if current scheduled notification is sent. I know it's weird because it's actually/already sent but I've check it again on that events.
But from the case, I know that method $notification->isSent() is always false.
I've looked at the code and found this line from this closed issue.
From that logic then I know that the result will always false because
event(new NotificationSent($this));
is firing before
$this->sent_at = Carbon::now();
$this->save();
I think it will be good to put it after update event so method like isSent()
still return true in notificationsSent listener.
I'm having this scenario:
This works.
But I'm having problem when user change $targetDay.
I'm listening to models "updated" event and I know there is "reschedule" method available in ScheduledNotifications.
But to call "reschedule", I need to have reference to $notification.
From your example: $notification->reschedule($rescheduleAt)
What would be the best way to get that reference?
I guess I should be able to get reference from this 3 parameters:
Or should I use completely different approach to handle situations like this?
Hello,
I have an AnonymousNotifiable and want to change the email only. For example the user changes his email so I want to update the notification. Otherwise it will be send to the old one.
How can I do that?
Thanks
Great job on the package!
I would like to add some additional fields on the migration - therefore it would be great if the migration wouldn't get loaded automatically from the service provider, but if I could just publish and modify it instead.
Would you accept a PR with that change?
Hi,
thanks a lot for your amazing work.
I would like to understand the given error. According to the documentation in the README file, I should have a Model like this:
class User extends Model {
use SnoozeNotifiable;
// ...
}
that sadly fires the error in the issue subject.
If look closer, the error is thrown in lines 46-48 of ScheduledNotification.php:
if (! method_exists($notifiable, 'notify')) {
throw new SchedulingFailedException(sprintf('%s is not notifiable', get_class($notifiable)));
}
if fact, looking at Traits/SnoozeNotifiable.php I see that only the notifyAt
method is declared, but not notify
.
The error disappear if I declare the Model as
use Notifiable, SnoozeNotifiable;
// ...
}
Anyway I would like to know if there's a mistake somewhere in my code, or "simply" something to add in the README.
version "1.0.5"
Laravel "v6.20.27"
Hi,
I'm using https://github.com/alsofronie/eloquent-uuid in my models and my ID fields are binary. Because of this I'm getting this error:
Adding toArray method in my model has no one effects.
Any idea?
Hey @thomasjohnkane ,
Thanks for the wonderful package.
I am having the following issue often while unserialize the content. it clearly shows couldn't unserialize data but serialize & unserialize are via the package.
when unserialize fails it's crashing, and unserialize has no way to catch the exception as well.
It automatically retries N times based on tolerance time and it crashes N times.
Please let me know is there any work around for this?
domain/username/Message
unserialize(): Error at offset 6079 of 18968 bytes
Level
ERROR
Exception
"class": "ErrorException",
"message": "unserialize(): Error at offset 6079 of 18968 bytes",
"code": 0,
"file": "/username/web/domain/vendor/thomasjohnkane/snooze/src/Serializer.php:34",
"trace": [
"/username/web/domain/vendor/thomasjohnkane/snooze/src/Serializer.php:34",
"/username/web/domain/vendor/thomasjohnkane/snooze/src/Models/ScheduledNotification.php:66",
"/username/web/domain/vendor/thomasjohnkane/snooze/src/Console/Commands/SendScheduledNotifications.php:58",
"/username/web/domain/vendor/laravel/framework/src/Illuminate/Support/Collection.php:475",
"/username/web/domain/vendor/thomasjohnkane/snooze/src/Console/Commands/SendScheduledNotifications.php:63",
"/username/web/domain/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:32",
"/username/web/domain/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:90",
"/username/web/domain/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:34",
"/username/web/domain/vendor/laravel/framework/src/Illuminate/Container/Container.php:576",
"/username/web/domain/vendor/laravel/framework/src/Illuminate/Console/Command.php:183",
"/username/web/domain/vendor/symfony/console/Command/Command.php:255",
"/username/web/domain/vendor/laravel/framework/src/Illuminate/Console/Command.php:170",
"/username/web/domain/vendor/symfony/console/Application.php:1001",
"/username/web/domain/vendor/symfony/console/Application.php:271",
"/username/web/domain/vendor/symfony/console/Application.php:147",
"/username/web/domain/vendor/laravel/framework/src/Illuminate/Console/Application.php:90",
"/username/web/domain/โฆ
in laravel version "version": "v7.14.1", i got this error, i found databse notification field data is not right,
O:41:"App\Notifications\AppointmentNotification":10:{s:11:"
it's missing something. Why?
i have a Appointment model to store user's appoinment,
and how can i get the notification by Appointment id? if user change the appointment time, i need to reschedule the notification, i only can get the notification by user id / notification type
I think having the flags (sent, rescheduled, cancelled) as datetime fields would be useful. It would help with debugging to know when the action happened.
It would be useful if we had a way to retrieve the underlying Illuminate\Notifications\Notification
from the ScheduledNotification
class. It's already part of the Eloquent model so it'd be handy to have a getNotification()
method. There's already functionality for unserializing it.
Should't we have ->onOneServer()
option set on the scheduler?
https://laravel.com/docs/8.x/scheduling#running-tasks-on-one-server
can it works on php 7.1? composer.json block it for now
Is the package still maintained? Will there be an update for Laravel 9?
StyleCI is migrating to a new payment system, and you must re-enter your payment information as soon as possible to continue using the StyleCI Monthly Solo plan. Please re-enter your payment details on the StyleCI account settings page, or directly by clicking here.
Please why notification not sent at send_at ?
I am trying to do this but I get a json error. Is there an easier way to cancel a notification by findyByTargetAndType?
`
$scheduledNotification=ScheduledNotification::findByTarget($user);
foreach ($scheduledNotification as $key ) {
print_r('yes');
if($key->getType() == 'App\Notifications\BookAMassageReminderNotificationApp')
{
print_r('yes');
}
else{
print_r('no');
}
}`
After installing the package when I was going to run php artisan migrate
.
It shows me
Illuminate\Database\QueryException
SQLSTATE[42000]: Syntax error or access violation: 1103 Incorrect table name '' (SQL: create table `` (
idint unsigned not null auto_increment primary key,
target_idvarchar(255) null,
target_typevarchar(255) not null,
targettext not null,
notification_typevarchar(255) not null,
notificationtext not null,
send_atdatetime not null,
sent_atdatetime null,
rescheduled_atdatetime null,
cancelled_atdatetime null,
created_attimestamp null,
updated_at timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci')
I have published the config file.
Versions:
Laravel Framework 7.30.4
PHP 7.4.15
Is there a way to add custom data to a notification? For example, writing an email or SMS and then scheduling that notification ? I can see there is a link in the documentation for support custom data, however it no longer exists, and the custom code example files are no longer in the documentation. Currently, when trying to do this, the notification just doesn't send.
Hi, I did create a notification from a model:
$finance->notifyAt(new ThreeConsecutiveNsfsDayOneEmail(), $this->due);
Now, I need to cancel this notification, the documentation is saying $notification->cancel();
but how can I have the notification. I tried the following but didn't work.
$notification = new ThreeConsecutiveNsfsDayOneEmail();
$notification->cancel();
So, what is the solution to do so, can you update the documentation.
Thank you,
If I understand the docs, I should be able to add a public function shouldInterrupt($notifiable)
to my class MyCoolNotification extends Notification
, something like:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class MyCoolNotification extends Notification
{
use Queueable;
public function shouldInterrupt($notifiable) {
return $notifiable->my_bool_value;
}
}
but I get an exception: Too few arguments to function App\Notifications\MyCoolNotification::shouldInterrupt(), 0 passed in ..............\vendor\thomasjohnkane\snooze\src\Models\ScheduledNotification.php on line 95 and exactly 1 expected
in that line 95 you call: return (bool) $notification->shouldInterrupt();
I think you are missing passing the $notifiable ??
how i can get id after send notification $user->notifyAt(some_notification_class)
i want stored in my table to cancel specific notification for user.
for cancel notification i use
$scheduledNotification= ScheduledNotification::find(scheduled_notification_id); $scheduledNotification->cancel();
There's currently no mechanism to clean up send/cancelled notifications. Over time the table will grow and grow, so we should probably have some way of cleaning up old entries.
Just moving this from the readme so we can discuss ๐
I think we should add an event dispatched before and after a notification is sent.
It would allow the application to do some checks before the notification is sent (ie, ensure that the user is still active, etc) and after (record that x email was sent)
Hello,
great package!
But is it possible to get the scheduled_notification by the meta tag but also eager load the target?
Use case:
I have tasks
The task has reminder notifications
The target is the selected user of the task notification
The task is stored in the meta data
I get all reminders / notificaitons for a task with findByMeta as a task attribute
Now a solution could be iterating with a foreach through every notification of the getRemindersAttribute function.
But is it build in and i couldnt figure it out?
Hello,
I am a little confused by the following behaviour.
// this is working
Notification::send(
$event->user, // Target
new DripMarketingNotification($rule)
);
// this is not
ScheduledNotification::create(
$event->user, // Target
new DripMarketingNotification($rule),
Carbon::now()->addSeconds($rule->delay) // Send At
);
The scheduled notification appears in the DB table, but when I run artisan schedule:run
I get the following error in the logs:
Undefined property: $dripRule {"exception":"[object] (ErrorException(code: 0) at .../src/Notifications/DripMarketingNotification.php:43)
But the regular Notification facade works perfectly. Is there something I am missing?
This is the code from DripMarketingNotification.php
public function toMail($notifiable)
{
return (new DripMarketingMail($notifiable, $this->dripRule))->to($notifiable->email);
}
I had a bug where one of the notifications was updated, but the previously serialized version had some invalid data in it.
This caused problems because snooze tries (and fails) to send it every minute.
We should have some kind of 'try' limit, to make sure we don't keep trying (and failing) to send the same notification.
I have done all the configuration and the notifications are being stored in the scheduled notifications table but when I run the "php artisan snooze:send" command it says no scheduled notifications need to be sent.
Hello,
first of all thank you so much for creating this package.. How do I implement multitenancy into this package?
I am currently creating an application that uses the multitenancy feature with the archtechx/tenancy package. I have already created a duplicate of the scheduled_notifications table in the tenant database, but I am unable to perform the php artisan snooze:send
command because this actions will trigger to the central database while the notification data is located in the tenant database.
I want to show all scheduled message by authenticate user. But I did not find any documentation about it.
I've look through the source code and found method findByTarget()
. Is that related method to get all scheduled notifications by current authenticated user?
And I saw at table, especially notification column. I wonder how I get my custom data because it's like a pattern right there (not the same like notifications data on default laravel notifications table)
Does it only have email notifications or it also supports sms notifications?
Hi,
first of all thank you so much for creating this package.. does this package support bulk, multiple notifiables? just like laravel Notification::send()
if($request->schedule && !empty($request->scheduled_at))
{
$enrolledUsers = User::whereRelation('enrolledCourses', 'course_id', $course_id)->get();
ScheduledNotification::create(
$enrolledUsers, // Target
new NewLessonNotification($lesson), // Notification
Carbon::createFromFormat('d/m/Y h:i a', $request->scheduled_at) // Send At
); // gives me error: Collection is not notifiable..
} else {
$enrolledUsers = User::whereRelation('enrolledCourses', 'course_id', $course_id)->get();
Notification::send($enrolledUsers, new NewLessonNotification($lesson));
}
Currently we just log an errors that happen when sending scheduled emails (to avoid breaking future sends in that batch).
justaphpguy
on reddit raised that we should use the report
hepler instead, which means it's passed onto things like Sentry, etc.
Ref: https://laravel.com/docs/5.7/errors#report-method
Pretty cool! ๐
I wonder though if the error handling in the console is a good idea => https://github.com/thomasjohnkane/snooze/blob/master/src/Console/Commands/SendScheduledNotifications.php#L55-L64
php try { $notification->send(); } catch (\Exception $e) { $this->error($e->getMessage()); Log::error(sprintf('Failed to send notification: %s', $e->getMessage())); }
Since the command is the primary way this is used with the scheduler, I believe this should be improved.
Sending to $this->error() and Log::error() is nice, but in reality you want to funnel this through the application exception handler so you can have proper reporting.
This removes the need for Log:error, not sure about $this->error().
php try { โฆ } catch (\Throwable $t) { report($e); $this->error($e->getMessage()); } Just my 2c ;)
I'm trying to make for my backend to send a notification each day that that comes closer to an indicated date.
For example, if my user adds the date "16-07-2020", he should be getting a notification "your deadline is in 1 day!" (as today is 15).
How is it possible to make it with this package?
Hello,
thank you for amazing package.
I have started getting lots of sentry errors with internal exceptions. Here is the trace:
Error: The script tried to call a method on an incomplete object. Please ensure that the class definition "App\Notifications\ReminderOnboard" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition
#19 /vendor/thomasjohnkane/snooze/src/Models/ScheduledNotification.php(103): method_exists
#18 /vendor/thomasjohnkane/snooze/src/Models/ScheduledNotification.php(103): Thomasjohnkane\Snooze\Models\ScheduledNotification::shouldInterrupt
#17 /vendor/thomasjohnkane/snooze/src/Models/ScheduledNotification.php(73): Thomasjohnkane\Snooze\Models\ScheduledNotification::send
#16 /vendor/thomasjohnkane/snooze/src/Console/Commands/SendScheduledNotifications.php(58): Thomasjohnkane\Snooze\Console\Commands\SendScheduledNotifications::Thomasjohnkane\Snooze\Console\Commands\{closure}
#15 /vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(244): Illuminate\Support\Collection::each
#14 /vendor/thomasjohnkane/snooze/src/Console/Commands/SendScheduledNotifications.php(63): Thomasjohnkane\Snooze\Console\Commands\SendScheduledNotifications::handle
#13 /vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}
#12 /vendor/laravel/framework/src/Illuminate/Container/Util.php(40): Illuminate\Container\Util::unwrapIfClosure
#11 /vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\Container\BoundMethod::callBoundMethod
#10 /vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\Container\BoundMethod::call
#9 /vendor/laravel/framework/src/Illuminate/Container/Container.php(653): Illuminate\Container\Container::call
#8 /vendor/laravel/framework/src/Illuminate/Console/Command.php(136): Illuminate\Console\Command::execute
#7 /vendor/symfony/console/Command/Command.php(298): Symfony\Component\Console\Command\Command::run
#6 /vendor/laravel/framework/src/Illuminate/Console/Command.php(121): Illuminate\Console\Command::run
#5 /vendor/symfony/console/Application.php(1015): Symfony\Component\Console\Application::doRunCommand
#4 /vendor/symfony/console/Application.php(299): Symfony\Component\Console\Application::doRun
#3 /vendor/symfony/console/Application.php(171): Symfony\Component\Console\Application::run
#2 /vendor/laravel/framework/src/Illuminate/Console/Application.php(94): Illuminate\Console\Application::run
#1 /vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(129): Illuminate\Foundation\Console\Kernel::handle
#0 /artisan(37): null
UPDATE:
Found the problem. The notification file was moved to another folder, but the records in scheduled_notifications
database table had old file path.
How this case could be solved?
How can i use this snooze Notification with any kind of paid sms api?
Hi
I'm getting the following error in my schedule:run
cron job
[2020-08-06 13:56:02] local.ERROR: There are no commands defined in the "snooze" namespace. {"exception":"[object] (Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException(code: 0): There are no commands defined in the \"snooze\" namespace. at /home2/foldernamechanged/public_html/testing/vendor/symfony/console/Application.php:597)
[stacktrace]
#0 /home2/foldernamechanged/public_html/testing/vendor/symfony/console/Application.php(650): Symfony\\Component\\Console\\Application->findNamespace('snooze')
#1 /home2/foldernamechanged/public_html/testing/vendor/symfony/console/Application.php(235): Symfony\\Component\\Console\\Application->find('snooze:send')
#2 /home2/foldernamechanged/public_html/testing/vendor/symfony/console/Application.php(147): Symfony\\Component\\Console\\Application->doRun(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#3 /home2/foldernamechanged/public_html/testing/vendor/laravel/framework/src/Illuminate/Console/Application.php(90): Symfony\\Component\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#4 /home2/foldernamechanged/public_html/testing/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(133): Illuminate\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#5 /home2/foldernamechanged/public_html/testing/artisan(36): Illuminate\\Foundation\\Console\\Kernel->handle(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput))
#6 {main}
"}
sendFrequency
is set to everyMinute
so I'm getting this error every minute now.
When I manually run schedule:run
or snooze:send
in console it works fine. The issue seems to occur only in the cron job.
Running php artisan
shows
snooze
snooze:prune Prune scheduled notifications that have been sent or cancelled
snooze:send Send scheduled notifications that are ready to be sent.
Searching the web, most answers were to run config:clear
, cache:clear
, composer dump-autoload
, but no luck doing that.
Any ideas on what could be wrong?
php: 7.2.32
laravel: 5.8.38
snooze: 1.0.3
os: CentOS Linux release 7.8.2003 (Core)
For example, when a job fails part way through and is retried it's possible to end up with a bunch of duplicate scheduled notifications.
Detecting this and throwing an exception or maybe silent fail?
Should be behind a config option
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.