Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Deprecated the AdvancedUserInterface #23508

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 4, 2018
Merged

Deprecated the AdvancedUserInterface #23508

merged 1 commit into from
Feb 4, 2018

Conversation

linaori
Copy link
Contributor

@linaori linaori commented Jul 14, 2017

Q A
Branch? 3.4
Bug fix? no
New feature? no
BC breaks? no
Deprecations? yes
Tests pass? yes
Fixed tickets #23292
License MIT
Doc PR ~

This PR deprecates the usages of the AdvancedUserInterface.

UPGRADE-3.4.md Outdated
Security
--------

* Using the AdvancedUserInterface is now deprecated. To use the existing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AdvancedUserInterface should be enclosed with backticks

UPGRADE-3.4.md Outdated
--------

* Using the AdvancedUserInterface is now deprecated. To use the existing
functionality, create a custom user-checker based off the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on

UPGRADE-3.4.md Outdated
removed in Symfony 4.0.

* The in-memory user no longer uses the `AdvancedUserInterface` and has the
functionality inlined.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isnt this a BC break?

UPGRADE-4.0.md Outdated
@@ -475,6 +475,14 @@ Security
* The `AccessDecisionManager::setVoters()` method has been removed. Pass the
voters to the constructor instead.

* Using the AdvancedUserInterface is now deprecated. To use the existing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in 4.0 the AdvancedUserInterface would be removed right?

@@ -32,6 +32,7 @@
*
* @see UserInterface
* @see AccountStatusException
* @deprecated This interface is deprecated as of 3.4 and will be removed in 4.0.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@deprecated since 3.4, to be removed in 4.0 something like that i believe. Also missing a runtime deprecation? i.e. trigger_error

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@deprecated since version 3.4, will be removed in 4.0.
(but no runtime notice because that'd trigger it for existing classes in core)

@@ -47,7 +46,7 @@
* and populated in any number of different ways when the user object
* is created.
*
* @return (Role|string)[] The user roles
* @return Role|string[] The user roles
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be reverted, it's intended as PSR-5 doc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm PhpStorm did not recognize this notation and PSR-5 is still not finished

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be Role[]|string[] then I guess?

Copy link
Contributor

@ro0NL ro0NL Jul 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

¯_(ツ)_/¯ technically that's an array of either strings or roles, whereas PSR-5 allows a mixed array.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should stay (Role|string)[] it's an array that can contains a mix of both Role objects and strings

}

/**
* @group legacy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing @expectedDeprecation?

@ro0NL
Copy link
Contributor

ro0NL commented Jul 15, 2017

Btw if we deprecate AdvancedUserInterace, i dont see the need to inline those methods into User (as a side effect); we could deprecate those in turn as well. Probably allows to cleanup further :)

@@ -18,7 +18,7 @@
*
* @author Fabien Potencier <[email protected]>
*/
final class User implements AdvancedUserInterface
final class User implements UserInterface, EquatableInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider this instead;

final class User implements UserInterface, EquatableInterface, AdvancedUserInterface

It should work just fine : https://3v4l.org/eRO4P, and avoids a BC-break for code that does this: $user instanceof AdvancedUserInterface

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's what I've been thinking off as well after a discussion with @ro0NL on slack. On one side it feels like this behavior shouldn't be used too often, but I also know that if something can happen, it will happen.

I just need to find a way to not trigger a deprecation for that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just need to find a way to not trigger a deprecation for that.

In the user checker? I guess you could check the classname before triggering, and if it is the core user class, don't trigger.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at RoleInterface; i think soft deprecating is fine. Implementing EquatableInterface is a new feature really. Perhaps simply revert this line?

@linaori
Copy link
Contributor Author

linaori commented Jul 15, 2017

@ro0NL They are already in the User, so it's merely making them a class only set of functions. I was thinking if we could remove those fields and limit it to a disabled/enabled, but this would influence the messages to the user based on the getMessageKey.

@linaori
Copy link
Contributor Author

linaori commented Jul 15, 2017

Side note, I was thinking of opening an RFC to rename the User to InMemoryUser, as it seems too generic right now. This would also allow cleanup of all those methods.

@ro0NL
Copy link
Contributor

ro0NL commented Jul 15, 2017

I just need to find a way to not trigger a deprecation for that.

rename the User to InMemoryUser

Deprecate User, add InMemoryUser... problem solved?

@linaori
Copy link
Contributor Author

linaori commented Jul 15, 2017

That could make the deprecations of User complete and simply use a smaller InMemory user anyway, Might solve more issues

@javiereguiluz
Copy link
Member

Please, don't deprecate User by InMemoryUser. It's a really bad name. Remember that Symfony should do the normal simple and the custom possible. The normal is to have a simple user in the database and represent it with a User entity. Thanks!

@linaori
Copy link
Contributor Author

linaori commented Jul 15, 2017

@javiereguiluz the User is the InMemoryUser and should only be used for the in memory provider. Sadly, due to the generic name, this is often mistaken as "the" user class.

@javiereguiluz
Copy link
Member

@iltar I'm sorry. I should have checked twice before commenting (I was on the phone). If this is the non-persisted user, then InMemoryUser is a perfect name because it's used in other frameworks/technologies too.

@nicolas-grekas nicolas-grekas added this to the 3.4 milestone Jul 17, 2017
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some random comments :)

@@ -16,6 +16,8 @@
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\SwitchUserRole;
use Symfony\Component\Security\Core\User\User;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alpha order

@@ -16,6 +16,7 @@
use Symfony\Bridge\Doctrine\Tests\Fixtures\User;
use Symfony\Bridge\Doctrine\Security\User\EntityUserProvider;
use Doctrine\ORM\Tools\SchemaTool;
use Symfony\Component\Security\Core\User\UserInterface;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

local alpha order: should be moved one line up

@@ -156,7 +157,7 @@ public function testLoadUserByUserNameShouldLoadUserWhenProperInterfaceProvided(
->method('loadUserByUsername')
->with('name')
->willReturn(
$this->getMockBuilder('\Symfony\Component\Security\Core\User\UserInterface')->getMock()
$this->getMockBuilder(UserInterface::class)->getMock()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert all the non required ::class, we favor helping future merges than doing these CS updates

@@ -47,7 +46,7 @@
* and populated in any number of different ways when the user object
* is created.
*
* @return (Role|string)[] The user roles
* @return Role|string[] The user roles
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be Role[]|string[] then I guess?

@@ -264,6 +264,7 @@ private function hasUserChanged(UserInterface $user)
}

if ($this->user instanceof AdvancedUserInterface && $user instanceof AdvancedUserInterface) {
@trigger_error(sprintf('Checking for the AdvancedUserInterface in %s has been deprecated in 3.4 and will be removed in 4.0. Implement the %s to check if the user has been changed,', __METHOD__, EquatableInterface::class), E_USER_DEPRECATED);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps I should check for the in memory user class here as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's equatable now.. so it wont get here right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The User, yes. The custom implementations of the AdvancedUserInterface, no

public function testIsEqualToWithDifferentUser()
{
$user = new User('username', 'password');
$this->assertFalse($user->isEqualTo($this->createMock(UserInterface::class)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be getMockBuilder(UserInterface::class)->getMock() (see travis)

@linaori
Copy link
Contributor Author

linaori commented Aug 14, 2017

@chalasr tests should be green now

@@ -28,10 +28,14 @@ class UserChecker implements UserCheckerInterface
*/
public function checkPreAuth(UserInterface $user)
{
if (!$user instanceof AdvancedUserInterface) {
if (!$user instanceof AdvancedUserInterface && !$user instanceof User) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do this? this will break any custom advanced user implem

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously it would return early if it wasn't an AdvancedUserInterface. In the future, this will be only if it's not a User (InMemoryUser). That's what I meant with the confusion about the naming.

return false;
}

if ($this->isAccountNonExpired() !== $user->isAccountNonExpired()) {
Copy link
Member

@chalasr chalasr Aug 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't assume that this method exists on $user class since it can be any UserInterface implementation which does not provide it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, missed the early return

Copy link
Member

@chalasr chalasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for pushing toward custom user checkers, the community seems to think it's worth dropping this interface.

@linaori
Copy link
Contributor Author

linaori commented Sep 25, 2017

Squashed and rebased against 3.4 to solve merge conflicts

@nicolas-grekas
Copy link
Member

@iltar sorry another rebase is needed

@linaori
Copy link
Contributor Author

linaori commented Sep 27, 2017

@nicolas-grekas fixed

@@ -184,11 +185,9 @@ public function testSetUser($user)

public function getUsers()
{
$user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
$advancedUser = $this->getMockBuilder('Symfony\Component\Security\Core\User\AdvancedUserInterface')->getMock();
$user = $this->getMockBuilder(UserInterface::class)->getMock();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all the non required "string to ::class" CS changes should be reverted to fit our policy and help reduce future merge conflicts as much as possible

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed all usages in my changes to use the strings (in upcoming push). Due to how the diffing works, some of them are not displaying it correctly, as methods have been added/removed. By using the string everywhere, it should be less confusing for git as well.

* @group legacy
*
* @expectedDeprecation Calling Symfony\Component\Security\Core\User\UserChecker::checkPostAuth with an AdvancedUserInterface is deprecated as of 3.4 and will be removed in 4.0. Create a custom user checker if you wish to keep this functionality.
*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra blank line (same in other places)

@@ -32,6 +32,7 @@
*
* @see UserInterface
* @see AccountStatusException
* @deprecated This interface is deprecated as of 3.4 and will be removed in 4.0.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@deprecated since version 3.4, will be removed in 4.0.
(but no runtime notice because that'd trigger it for existing classes in core)

Copy link
Member

@xabbuh xabbuh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

except for my minor comments regarding the changelog

UPGRADE-3.4.md Outdated
@@ -277,6 +277,11 @@ Security
`DigestAuthenticationListener` and `DigestAuthenticationEntryPoint` will be
removed in 4.0. Use another authentication system like `http_basic` instead.

* Using the `AdvancedUserInterface` is now deprecated. To use the existing
functionality, create a custom user-checker based on the
`Symfony\Component\Security\Core\UserChecker`. This functionality will be
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Symfony\Component\Security\Core\User\UserChecker

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This interface will [...]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UserChecker !== UserCheckerInterface

Shouldnt we deprecate UserChecker? as it's tied to AdvancedUserInterface 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but imo it should be renamed to the InMemoryUserChecker (see other comments), just like the InMemoryUser. I wish to do this, but I don't have the time to do so before the feature freeze after this gets merged.

If you have time to do so, I'd gladly help out. I'm already stretching my time with non-project related stuff at the moment, so I can't handle another full PR within a few days

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. But in changelogs shouldnt we promote "based on UserCheckerInterface" instead?

Ill have a look at the InMemory story soonish :) i like it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xabbuh This particular reference (and the one for CHANGELOG.md) are correctly referring to the implementation, how the conditions work based on the advanced user interface.

@@ -13,6 +13,10 @@ CHANGELOG
the user will always be logged out when the user has changed between
requests.
* deprecated HTTP digest authentication
* Using the AdvancedUserInterface is now deprecated. To use the existing
functionality, create a custom user-checker based on the
`Symfony\Component\Security\Core\UserChecker`. This functionality will be
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Symfony\Component\Security\Core\User\UserChecker

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This interface will [...]

@nicolas-grekas
Copy link
Member

ping @iltar

@linaori
Copy link
Contributor Author

linaori commented Oct 2, 2017

Merge conflicts resolved and namespaces in the md files fixed as comment by xabbuh

@nicolas-grekas nicolas-grekas modified the milestones: 3.4, 4.1 Oct 24, 2017
@nicolas-grekas
Copy link
Member

Moving to 4.1 as 3.4 is in beta, thus closed for new feats.

@xabbuh
Copy link
Member

xabbuh commented Dec 11, 2017

@iltar Can you rebase and update the changelog/update entries to account for 4.1?

@linaori linaori changed the base branch from 3.4 to master December 11, 2017 09:38
@linaori
Copy link
Contributor Author

linaori commented Dec 11, 2017

@xabbuh should be fixed now

@chalasr
Copy link
Member

chalasr commented Jan 18, 2018

@fabpot still sceptical about this change? It would be good to move forward

@nicolas-grekas
Copy link
Member

(small rebase needed)

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Jan 24, 2018

I'm sorry to come late in the game with this question, but what's the purpose of this change? What's the expected benefit? Every new deprecation has a clear downside: it is asking users to, someday, change their code. That's a cost for sure. What's the other side of the balance that justifies this?

To be honest, I really don't know this part of Symfony, so I don't expect to understand your answer :)
But I'd really like that people who understand what's going on here to still have this reasoning, and that we take the decision on this basis.

Any hints?

@linaori
Copy link
Contributor Author

linaori commented Jan 24, 2018

@nicolas-grekas long story short: this particular part in Symfony is domain logic, rather than infrastructure.

// comes with
public function isAccountNonExpired();
public function isAccountNonLocked();
public function isCredentialsNonExpired();
public function isEnabled();

Those 4 "states" can be reused by an application, but usually does not. In addition to that, the code that everyone uses by default, has all kind of exceptions programmed for the advanced user interface.

  • The UserChecker doesn't do anything unless it's an advanced user
  • The AbstractToken (which pretty much every token extends), contains special branches for the AdvancedUserInterface

This kind of logic does (in my opinion), not belong in the core framework. If you don't use the AdvancedUserInterface, Security will still work, but will still contain the domain logic in all the core framework classes.

Symfony by default comes with 1 user class: Symfony\Component\Security\Core\User\User. By default, this user implements the AdvancedUserInterface. However, this user object, is only used for the InMemoryUserProvider. This particular provider (in theory) doesn't need domain logic, because you manage it from the security.yaml config. In any other case, the documentation tells the developer to implement the UserInterface themselves.

So to sum it up:

  • The AdvancedUserInterface causes the core framework to contain code branches in 2 core classes that is used by pretty much everyone, but never hit
  • It provides a some form of domain logic with the 4 methods listed above, that are pretty much never needed at all (or maybe subset thereof).
  • The method names are very confusing due to being negations

As far as I can tell, the AdvancedUserInterface is based on a subset of methods from the Spring user: https://docs.spring.io/spring-security/site/docs/2.0.7.RELEASE/apidocs/org/springframework/security/userdetails/UserDetails.html (much as other parts, like the SecurityContext were based on). I feel that Symfony does not need this by default.

If this PR comes through:

  • There will be less User related interfaces and branches for a new developer to get confused by
  • It opens the door to make a NullUserChecker which would become the default, the current user checker doesn't do anything without the interface anyway
  • It opens the door to add an InMemoryUserChecker, which could do the current checks, if they are still needed (which seems obsolete imo, due to the config being in security.yaml)
  • It opens the door to rename the current User to InMemoryUser, which is what it's used for

If you have any questions, I'll be happy to answer 👍

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor rebase needed)

@nicolas-grekas
Copy link
Member

Thank you @iltar.

@nicolas-grekas nicolas-grekas merged commit 8456f3b into symfony:master Feb 4, 2018
nicolas-grekas added a commit that referenced this pull request Feb 4, 2018
This PR was merged into the 4.1-dev branch.

Discussion
----------

Deprecated the AdvancedUserInterface

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #23292
| License       | MIT
| Doc PR        | ~

This PR deprecates the usages of the `AdvancedUserInterface`.

Commits
-------

8456f3b Deprecated the AdvancedUserInterface
*
* @dataProvider getUserChangesAdvancedUser
*/
public function testSetUserSetsAuthenticatedToFalseWhenUserChangesdvancedUser($firstUser, $secondUser)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an 'A' missing here to complete the word 'Advanced' :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heh, you're completely right! If you wish, you could make a PR to fix this (you can just click the edit file). Gives you a nice contributor tag

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do =) Thank you.

@@ -212,53 +209,59 @@ public function testSetUserSetsAuthenticatedToFalseWhenUserChanges($firstUser, $
}

public function getUserChanges()
{
$user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just wondering since I'm not too familiar with the Symfony testing guidelines: Wouldn't it be easier and more refactoring-friendly to use the ::class constants here instead of hand-writing the FQCN?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consistency in this case. I personally would update everything to use ::class, but that might cause merge conflicts for no reason when merging changes from lower branches upwards.

Copy link
Contributor

@keichinger keichinger Mar 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough :) Thanks!

Opened #26349

nicolas-grekas added a commit that referenced this pull request Mar 1, 2018
This PR was merged into the 4.1-dev branch.

Discussion
----------

Fix typo in test method name

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT

This fixes a small typo spotted in #23508 (see https://github.com/symfony/symfony/pull/23508/files/8456f3b32ce6ec394fb27b9fc9a2989ed54862b1#r171488418)

Commits
-------

e5734aa Fix typo in test method name
@fabpot fabpot mentioned this pull request May 7, 2018
@hAz4rd0uS
Copy link

Hi, what should we use now instead of AdvancedUserInterface ?

@chalasr
Copy link
Member

chalasr commented Jun 25, 2018

@h4ck3rm1k3 https://symfony.com/doc/current/security/user_checkers.html
Please consider reading the "fixed ticket" section of the PR body, discussion happened there :)

XWB pushed a commit to FriendsOfSymfony/FOSUserBundle that referenced this pull request Sep 19, 2018
* Migrated SF AdvancedUserInterface to FOS UserInterface

AdvancedUserInterface is deprecated since Symfony 4.1
- symfony/symfony#23508

Issue:
- #2803 Deprecation with Symfony 4.1 - AdvancedUserInterface

* Code style fixed and using `getMockBuilder` instead of `createMock`

* Code style fixed and using attributes instead of `$this->expectException`

* Change to restart travis

* EquatableInterface added to `UserInterface` and implementation added to `User`

* Tests after merge of master fixed

* Tests after merge of master fixed

* Update README.md

* Added compatibility for apps that check against AdvancedUserInterface

* Code style fixed to pass all travis tests

* fos_user.user_checker Service marked as non-public
@linaori linaori deleted the deprecation/advanced-user-interface branch February 8, 2019 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.