• 
      

    Add an admin page for viewing and managing licenses.

    Review Request #14404 — Created April 28, 2025 and submitted

    Information

    Review Board
    release-7.1.x

    Reviewers

    This adds a new dedicated Licenses page in the Admin UI for seeing all
    current registered licenses across License Providers. These indicate the
    state of the licenses, expiration information, provide license
    management, actions, and custom line items.

    Each license is represented by a License model and LicenseView view,
    backed by state provided by the License Provider. Custom models, views,
    and data can be provided as needed.

    Some basic infrastructure is set up for custom actions and license
    checks. To ease review, those capabilities will be introduced in a
    follow-up change.

    Python and JavaScript unit tests passed.

    Tested this with some custom License Providers registered in extensions
    as tests, and with Power Pack ported over to License Providers. Verified
    that all the state and status updates introduced in this change function
    as expected.

    Summary ID
    Add an admin page for viewing and managing licenses.
    This adds a new dedicated Licenses page in the Admin UI for seeing all current registered licenses across License Providers. These indicate the state of the licenses, expiration information, provide license management, actions, and custom line items. Each license is represented by a `License` model and `LicenseView` view, backed by state provided by the License Provider. Custom models, views, and data can be provided as needed. Some basic infrastructure is set up for custom actions and license checks. To ease review, those capabilities will be introduced in a follow-up change.
    61f43a312a3e05ef8a292a1a6272250b375cc82a

    Description From Last Updated

    'json' imported but unused Column: 1 Error code: F401

    reviewbot reviewbot

    'uuid.uuid4' imported but unused Column: 1 Error code: F401

    reviewbot reviewbot

    'reviewboard.licensing.errors.LicenseActionError' imported but unused Column: 1 Error code: F401

    reviewbot reviewbot

    'reviewboard.licensing.license_checks.ProcessCheckLicenseResult' imported but unused Column: 1 Error code: F401

    reviewbot reviewbot

    'reviewboard.licensing.license_checks.ProcessCheckLicenseResultStatus' imported but unused Column: 1 Error code: F401

    reviewbot reviewbot

    'djblets.util.typing.JSONValue' imported but unused Column: 5 Error code: F401

    reviewbot reviewbot

    'djblets.util.typing.SerializableJSONValue' imported but unused Column: 5 Error code: F401

    reviewbot reviewbot

    Why are we doing it this way instead of include('reviewboard.licensing.urls')? Seems like we should stay consistent.

    david david

    Should we define a TypedDict for this return type so we get warnings about if anything we're assigning isn't the …

    david david

    Switch these two import lines

    david david

    These should come from collections.abc, not typing

    david david

    Can we either mark this as internal (prefix with _) or add docstrings to it? Future docstring linting will complain …

    david david

    Same here.

    david david

    And here.

    david david

    Can we add doc comments on these?

    david david

    Please add a docstring.

    david david

    Please add a docstring.

    david david

    Please add a docstring.

    david david

    Please add a docstring.

    david david

    Seems like the T here got unintentionally capitalized.

    david david

    tuple -> dict

    david david

    This should fit on one line.

    david david

    I feel like it'd be nicer to get rid of all the inner if plan_name: ... else: ... statements, and …

    maubin maubin
    Checks run (1 failed, 1 succeeded)
    flake8 failed.
    JSHint passed.

    flake8

    chipx86
    david
    1. 
        
    2. reviewboard/admin/urls.py (Diff revision 2)
       
       
      Show all issues

      Why are we doing it this way instead of include('reviewboard.licensing.urls')? Seems like we should stay consistent.

    3. reviewboard/licensing/provider.py (Diff revision 2)
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      Should we define a TypedDict for this return type so we get warnings about if anything we're assigning isn't the right type?

      1. There's changes coming, so let me tackle this in a different change.

    4. Show all issues

      Switch these two import lines

    5. Show all issues

      These should come from collections.abc, not typing

    6. Show all issues

      Can we either mark this as internal (prefix with _) or add docstrings to it? Future docstring linting will complain otherwise.

    7. Show all issues

      Same here.

    8. Show all issues

      And here.

    9. Show all issues

      Can we add doc comments on these?

    10. Show all issues

      Please add a docstring.

    11. Show all issues

      Please add a docstring.

    12. Show all issues

      Please add a docstring.

    13. Show all issues

      Please add a docstring.

    14. reviewboard/licensing/views.py (Diff revision 2)
       
       
      Show all issues

      tuple -> dict

    15. Show all issues

      This should fit on one line.

    16. 
        
    chipx86
    david
    1. 
        
    2. Show all issues

      Seems like the T here got unintentionally capitalized.

      1. This was intentional. Because we're working with representations of elements and their properties and not HTML that gets normalized, we need to use the actual property names on the object. A HTMLTimeElement uses dateTime instead of datetime. My old implementation had an issue here.

    3. 
        
    maubin
    1. 
        
    2. reviewboard/licensing/provider.py (Diff revision 3)
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      I feel like it'd be nicer to get rid of all the inner if plan_name: ... else: ... statements, and instead have something like this:

      if plan_name:
          display_name = f'{product} ({plan_name})'
      else:
          display_name = f'{product}'
      

      And then use display_name in the summary strings.

      1. This is for localization purposes. When localizing strings, you don't always end up with the string in the same order you would in English, so if you compose it, you might get something wrong.

        For instance, while it may be {product} ({plan_name}) in English, another language could effectively want to reverse that, not use parens, change inflection, or have some other issue that couldn't be solved when separating this part of the string out.

      2. Ah got it.

    3. 
        
    maubin
    1. Ship It!
    2. 
        
    david
    1. Ship It!
    2. 
        
    chipx86
    Review request changed
    Status:
    Completed
    Change Summary:
    Pushed to release-7.1.x (1b9f858)