#3772 Hide expire API keys by default and add an option to show them
Merged 6 years ago by pingou. Opened 6 years ago by pingou.

file modified
+2 -2
@@ -242,7 +242,7 @@ 

    margin-left:2em;

  }

  

- .hidden, .milestone_inactive{

+ .hidden, .milestone_inactive, .expired_api_keys{

    display: none;

  }

  
@@ -338,4 +338,4 @@ 

  

  .line-height-1{

    line-height: 1em;

- } 

\ No newline at end of file

+ }

file modified
+12 -128
@@ -208,134 +208,7 @@ 

            {% endif %}

  

            <div class="tab-pane fade" id="apikeys-tab" role="tabpanel" aria-labelledby="apikeys-tab">

-             <h3 class="font-weight-bold mb-3">

-               API Keys

-               <a href="{{ url_for(

-                 'ui_ns.add_token',

-                 repo=repo.name,

-                 username=username,

-                 namespace=repo.namespace) }}" method="post" class="icon float-right">

-                   <button class="btn btn-sm btn-outline-primary" type="submit"

-                     title="Generate a new API token">

-                     Create new API Key

-                   </button>

-                   </a>

-             </h3>

-             <div class="row">

-               <div class="col">

-                 <p>

-                     API keys are tokens used to authenticate you on pagure. They can also

-                     be used to grant access to 3rd party application to behave on this

-                     project on your name.

-                   </p>

-                   <p>

-                     These are your personal tokens; they are not visible to the other

-                     admins of this repository.

-                   </p>

-                   <p>

-                     These keys are valid for <span class="strong">60</span> days.

-                   </p>

-                   <p>

-                     These keys are private to your project, make sure to store in a safe

-                     place and do not share it.

-                   </p>

-                   {% if repo.tokens %}

-                   {% for token in repo.tokens %}

-                     {% if token.user.username == g.fas_user.username %}

-                         <div class="form-group">

-                           <div class="input-group">

-                             <div class="input-group-prepend">

-                               <span class="input-group-text">

-                                 <span class="fa fa-key"></span>

-                                 <strong> {{ token.description or '' }}</strong>

-                               </span>

-                             </div>

-                             <div class="input-group-prepend">

-                               <span class="input-group-text">

-                                 <a href="#"

-                                   data-toggle="modal" data-target="#acls{{ token.id }}">

-                                   {{token.acls_list_pretty|length}} ACLs

-                                 </a>

-                               </span>

-                               <div class="modal fade" id="acls{{ token.id }}" tabindex="-1"

-                                     role="dialog" aria-labelledby="ACLs" aria-hidden="true">

-                                 <div class="modal-dialog" role="document">

-                                   <div class="modal-content">

-                                     <div class="modal-header">

-                                       <button type="button" class="close" data-dismiss="modal" aria-label="Close">

-                                         <span aria-hidden="true">&times;</span>

-                                         <span class="sr-only">Close</span>

-                                       </button>

-                                       <h4 class="modal-title" id="myModalLabel">ACLs</h4>

-                                     </div>

-                                     <div class="modal-body">

-                                       <ul>

-                                         {% for acl in token.acls_list_pretty %}

-                                           <li>{{ acl }}</li>

-                                         {% endfor %}

-                                       </ul>

-                                     </div>

-                                   </div>

-                                 </div>

-                               </div>

-                             </div>

- 

- 

-                             <input class="form-control bg-white" style="font-family:monospace" type="text" value="{{ token.id }}" readonly>

-                             {% if token.expired %}

-                               <span class="input-group-prepend">

-                                 <span class="input-group-text text-danger">

-                                   <small class="font-weight-bold">Expired on {{ token.expiration.date() }}</small>

-                                 </span>

-                               </span>

-                             {% else %}

-                               <span class="input-group-prepend">

-                                 <span class="input-group-text text-success">

-                                   <small class="font-weight-bold">Active until {{ token.expiration.date() }}</small>

-                                 </span>

-                               </span>

-                             {% endif %}

-                             {% if not token.expired %}

-                             <form action="{{ url_for(

-                               'ui_ns.revoke_api_token',

-                               repo=repo.name,

-                               username=username,

-                               namespace=repo.namespace,

-                               token_id=token.id) }}"

-                               method="post" class="icon">

-                               <button class="btn btn-outline-danger" type="submit"

-                                   onclick="return confirm('Are you sure to revoke this token ?'

-                                       + '\nThis will break all application using it and '

-                                       + 'cannot be un-done.');"

-                                   title="Revoke token">

-                                 <i class="fa fa-trash"></i>

-                               </button>

-                               {{ form.csrf_token }}

-                             </form>

-                             {% else %}

-                             <form action="{{ url_for(

-                               'ui_ns.renew_api_token',

-                               repo=repo.name,

-                               username=username,

-                               namespace=repo.namespace,

-                               token_id=token.id) }}"

-                               method="post" class="icon">

-                               <button class="btn btn-outline-primary" type="submit"

-                                   onclick="return confirm('Are you sure to renew this token ?'

-                                       + '\nIt will have the same ACL but will be a different key.');"

-                                   title="Renew token">

-                                 <i class="fa fa-refresh"></i>

-                               </button>

-                               {{ form.csrf_token }}

-                             </form>

-                             {% endif %}

-                           </div>

-                         </div>

-                     {% endif %}

-                   {% endfor %}

-                   {% endif %}

-               </div>

-             </div>

+               {% include 'settings_api_keys.html' %}

            </div>

  

            <div class="tab-pane fade" id="projectoptions-tab" role="tabpanel" aria-labelledby="projectoptions-tab">
@@ -1436,6 +1309,17 @@ 

      }

  });

  

+ $('#show_old_keys').click(function(e) {

+   var _el = $('.expired_api_keys')

+   if (_el.css('display') == 'none'){

+     _el.css('display', 'flex');

+     $('#show_old_keys').text('Hide old API keys');

+   } else {

+     $('#show_old_keys').text('Show old API keys');

+    _el.hide();

+   }

+ });

+ 

  {% if config.get('ENABLE_GIVE_PROJECTS', True)

            and repo.user.user == g.fas_user.username

            and not repo.is_fork %}

@@ -0,0 +1,140 @@ 

+ 

+ <div class="row mb-3">

+   <h3 class="col-6 font-weight-bold mb-3">

+     API Keys

+   </h3>

+   <div class="col-6 text-right">

+     <div class="btn-group">

+       <a href="{{ url_for(

+         'ui_ns.add_token',

+         repo=repo.name,

+         username=username,

+         namespace=repo.namespace) }}"

+           class="btn btn-sm btn-outline-primary"

+           title="Generate a new API token">

+         Create new API Key

+       </a>

+       <div class="btn-group">

+         <a href="javascript:void(0)" method="post" class="btn btn-sm btn-outline-primary"

+           title="Show old API token" id="show_old_keys">

+           Show old API Keys

+         </a>

+       </div>

+     </div>

+   </div>

+ </div>

+ 

+ <div class="row">

+   <div class="col">

+     <p>

+       API keys are tokens used to authenticate you on pagure. They can also

+       be used to grant access to 3rd party application to behave on this

+       project on your name.

+     </p>

+     <p>

+       These are your personal tokens; they are not visible to the other

+       admins of this repository.

+     </p>

+     <p>

+       These keys are valid for <span class="strong">60</span> days.

+     </p>

+     <p>

+       These keys are private to your project, make sure to store in a safe

+       place and do not share it.

+     </p>

+     {% if repo.tokens %}

+     {% for token in repo.tokens %}

+       {% if token.user.username == g.fas_user.username %}

+           <div class="form-group{% if token.expired %} expired_api_keys{% endif %}">

+             <div class="input-group">

+               <div class="input-group-prepend">

+                 <span class="input-group-text">

+                   <span class="fa fa-key"></span>

+                   <strong> {{ token.description or '' }}</strong>

+                 </span>

+               </div>

+               <div class="input-group-prepend">

+                 <span class="input-group-text">

+                   <a href="#"

+                     data-toggle="modal" data-target="#acls{{ token.id }}">

+                     {{token.acls_list_pretty|length}} ACLs

+                   </a>

+                 </span>

+                 <div class="modal fade" id="acls{{ token.id }}" tabindex="-1"

+                       role="dialog" aria-labelledby="ACLs" aria-hidden="true">

+                   <div class="modal-dialog" role="document">

+                     <div class="modal-content">

+                       <div class="modal-header">

+                         <button type="button" class="close" data-dismiss="modal" aria-label="Close">

+                           <span aria-hidden="true">&times;</span>

+                           <span class="sr-only">Close</span>

+                         </button>

+                         <h4 class="modal-title" id="myModalLabel">ACLs</h4>

+                       </div>

+                       <div class="modal-body">

+                         <ul>

+                           {% for acl in token.acls_list_pretty %}

+                             <li>{{ acl }}</li>

+                           {% endfor %}

+                         </ul>

+                       </div>

+                     </div>

+                   </div>

+                 </div>

+               </div>

+ 

+               <input class="form-control bg-white" style="font-family:monospace" type="text" value="{{ token.id }}" readonly>

+               {% if token.expired %}

+                 <span class="input-group-prepend">

+                   <span class="input-group-text text-danger">

+                     <small class="font-weight-bold">Expired on {{ token.expiration.date() }}</small>

+                   </span>

+                 </span>

+               {% else %}

+                 <span class="input-group-prepend">

+                   <span class="input-group-text text-success">

+                     <small class="font-weight-bold">Active until {{ token.expiration.date() }}</small>

+                   </span>

+                 </span>

+               {% endif %}

+               {% if not token.expired %}

+               <form action="{{ url_for(

+                 'ui_ns.revoke_api_token',

+                 repo=repo.name,

+                 username=username,

+                 namespace=repo.namespace,

+                 token_id=token.id) }}"

+                 method="post" class="icon">

+                 <button class="btn btn-outline-danger" type="submit"

+                     onclick="return confirm('Are you sure to revoke this token ?'

+                         + '\nThis will break all application using it and '

+                         + 'cannot be un-done.');"

+                     title="Revoke token">

+                   <i class="fa fa-trash"></i>

+                 </button>

+                 {{ form.csrf_token }}

+               </form>

+               {% else %}

+               <form action="{{ url_for(

+                 'ui_ns.renew_api_token',

+                 repo=repo.name,

+                 username=username,

+                 namespace=repo.namespace,

+                 token_id=token.id) }}"

+                 method="post" class="icon">

+                 <button class="btn btn-outline-primary" type="submit"

+                     onclick="return confirm('Are you sure to renew this token ?'

+                         + '\nIt will have the same ACL but will be a different key.');"

+                     title="Renew token">

+                   <i class="fa fa-refresh"></i>

+                 </button>

+                 {{ form.csrf_token }}

+               </form>

+               {% endif %}

+             </div>

+           </div>

+       {% endif %}

+     {% endfor %}

+     {% endif %}

+   </div>

+ </div>

@@ -7,76 +7,76 @@ 

    possible to create a roadmap for your project. Below you can create

    the milestones and optionally set dates for them.

  </p>

-         <form action="{{ url_for(

-               '.update_milestones',

-               repo=repo.name,

-               username=username,

-               namespace=repo.namespace, from=from or None) }}"

-             method="post" class="icon">

-           {{ tag_form.csrf_token }}

-             <div class="row">

-               <div class="col-sm-4">

-                 <strong>Milestone</strong>

-               </div>

-               <div class="col-sm-4">

-                 <strong>Date (optional)</strong>

-               </div>

-               <div class="col-sm-2">

-                 <strong>Reorder</strong>

-               </div>

-               <div class="col-sm-2">

-                 <strong>Active</strong>

-               </div>

-             </div>

-             <div id="milestones">

-           {% for milestone in (repo.milestones_keys or repo.milestones or [""]) %}

-               <div class="row p-t-1 milestone{%if milestone and

-               not repo.milestones[milestone]['active'] %} milestone_inactive {%

-               endif %}" id="milestone_{{ loop.index }}">

-                 <div class="col-sm-4 p-r-0">

-                   <input type="text" name="milestones"

-                     value="{{ milestone }}" size="3" class="form-control"/>

-                 </div>

-                 <div class="col-sm-4 p-r-0">

-                   <input type="text" name="milestone_date_{{ loop.index }}"

-                     value="{{ repo.milestones[milestone]['date']

-                         if milestone and repo.milestones[milestone]['date'] is not none

-                     }}" class="form-control"/>

-                 </div>

-                 <div class="col-sm-2 p-r-0" >

-                     <span class="fa fa-long-arrow-up milestone_order_up"

-                         data-stone="{{ loop.index }}"></span>

-                     <span class="fa fa-long-arrow-down milestone_order_bottom"

-                         data-stone="{{ loop.index }}"></span>

-                 </div>

-                 <div class="col-sm-1 p-r-0" >

-                     <input type="checkbox" name="active_milestone_{{ loop.index

-                     }}"{% if milestone and repo.milestones[milestone]['active']

-                     %} checked{% endif %} />

-                 </div>

-               </div>

-           {% endfor %}

-           </div>

-           <div class="row p-t-1">

-             <div class="col-sm-6">

-               <a href="javascript:void(0)" class="btn btn-outline-primary btn-sm btn-block extend-form mt-1"

-                 data-target="#milestones">

-                   <i class="fa fa-plus"></i> Add new milestone

-               </a>

-             </div>

-             <div class="col-sm-6">

-               <a href="javascript:void(0)" class="btn btn-outline-primary btn-sm btn-block extend-form mt-1"

-                 data-target="#milestones_show">

-                   <i class="fa fa-repeat"></i> Show all milestones

-               </a>

-             </div>

-           </div>

-           <div class="row p-t-1">

-             <div class="col-sm-12">

-               <button class="btn btn-primary float-right mt-3" type="submit"

-                   title="Update the milestones">

-                 Update

-               </button>

-             </div>

-           </div>

-         </form>

+ <form action="{{ url_for(

+       '.update_milestones',

+       repo=repo.name,

+       username=username,

+       namespace=repo.namespace, from=from or None) }}"

+     method="post" class="icon">

+   {{ tag_form.csrf_token }}

+     <div class="row">

+       <div class="col-sm-4">

+         <strong>Milestone</strong>

+       </div>

+       <div class="col-sm-4">

+         <strong>Date (optional)</strong>

+       </div>

+       <div class="col-sm-2">

+         <strong>Reorder</strong>

+       </div>

+       <div class="col-sm-2">

+         <strong>Active</strong>

+       </div>

+     </div>

+     <div id="milestones">

+   {% for milestone in (repo.milestones_keys or repo.milestones or [""]) %}

+       <div class="row p-t-1 milestone{%if milestone and

+       not repo.milestones[milestone]['active'] %} milestone_inactive {%

+       endif %}" id="milestone_{{ loop.index }}">

+         <div class="col-sm-4 p-r-0">

+           <input type="text" name="milestones"

+             value="{{ milestone }}" size="3" class="form-control"/>

+         </div>

+         <div class="col-sm-4 p-r-0">

+           <input type="text" name="milestone_date_{{ loop.index }}"

+             value="{{ repo.milestones[milestone]['date']

+                 if milestone and repo.milestones[milestone]['date'] is not none

+             }}" class="form-control"/>

+         </div>

+         <div class="col-sm-2 p-r-0" >

+             <span class="fa fa-long-arrow-up milestone_order_up"

+                 data-stone="{{ loop.index }}"></span>

+             <span class="fa fa-long-arrow-down milestone_order_bottom"

+                 data-stone="{{ loop.index }}"></span>

+         </div>

+         <div class="col-sm-1 p-r-0" >

+             <input type="checkbox" name="active_milestone_{{ loop.index

+             }}"{% if milestone and repo.milestones[milestone]['active']

+             %} checked{% endif %} />

+         </div>

+       </div>

+   {% endfor %}

+   </div>

+   <div class="row p-t-1">

+     <div class="col-sm-6">

+       <a href="javascript:void(0)" class="btn btn-outline-primary btn-sm btn-block extend-form mt-1"

+         data-target="#milestones">

+           <i class="fa fa-plus"></i> Add new milestone

+       </a>

+     </div>

+     <div class="col-sm-6">

+       <a href="javascript:void(0)" class="btn btn-outline-primary btn-sm btn-block extend-form mt-1"

+         data-target="#milestones_show">

+           <i class="fa fa-repeat"></i> Show all milestones

+       </a>

+     </div>

+   </div>

+   <div class="row p-t-1">

+     <div class="col-sm-12">

+       <button class="btn btn-primary float-right mt-3" type="submit"

+           title="Update the milestones">

+         Update

+       </button>

+     </div>

+   </div>

+ </form>

@@ -1433,25 +1433,25 @@ 

              # Check that the milestones have their empty fields

              self.assertIn(

              '''<div id="milestones">

-               <div class="row p-t-1 milestone" id="milestone_1">

-                 <div class="col-sm-4 p-r-0">

-                   <input type="text" name="milestones"

-                     value="" size="3" class="form-control"/>

-                 </div>

-                 <div class="col-sm-4 p-r-0">

-                   <input type="text" name="milestone_date_1"

-                     value="" class="form-control"/>

-                 </div>

-                 <div class="col-sm-2 p-r-0" >

-                     <span class="fa fa-long-arrow-up milestone_order_up"

-                         data-stone="1"></span>

-                     <span class="fa fa-long-arrow-down milestone_order_bottom"

-                         data-stone="1"></span>

-                 </div>

-                 <div class="col-sm-1 p-r-0" >

-                     <input type="checkbox" name="active_milestone_1" />

-                 </div>

-               </div>''', output_text)

+       <div class="row p-t-1 milestone" id="milestone_1">

+         <div class="col-sm-4 p-r-0">

+           <input type="text" name="milestones"

+             value="" size="3" class="form-control"/>

+         </div>

+         <div class="col-sm-4 p-r-0">

+           <input type="text" name="milestone_date_1"

+             value="" class="form-control"/>

+         </div>

+         <div class="col-sm-2 p-r-0" >

+             <span class="fa fa-long-arrow-up milestone_order_up"

+                 data-stone="1"></span>

+             <span class="fa fa-long-arrow-down milestone_order_bottom"

+                 data-stone="1"></span>

+         </div>

+         <div class="col-sm-1 p-r-0" >

+             <input type="checkbox" name="active_milestone_1" />

+         </div>

+       </div>''', output_text)

  

              # Check that the close_status have its empty field

              self.assertIn(
@@ -4318,7 +4318,6 @@ 

          output_text = output.get_data(as_text=True)

          self.assertIn('0.0.1', output_text)

          self.assertIn('<section class="tag_list">', output_text)

-         print(output_text)

          self.assertEqual(

              output_text.count('<i class="fa fa-calendar-o fa-rotate-270 text-muted"></i>'),

              1)
@@ -5051,9 +5050,9 @@ 

              self.assertIn('<h5 class="pl-2 font-weight-bold text-muted">Project Settings</h5>', output_text)

              self.assertIn('<strong> Test token</strong>', output_text)

              self.assertIn(

-                 '<span class="input-group-text text-success">\n                                  '

-                 '<small class="font-weight-bold">Active until',

-                 output_text)

+                 '<span class="input-group-text text-success">'

+                 '\n                    <small class="font-weight-bold">'

+                 'Active until', output_text)

  

      @patch('pagure.decorators.admin_session_timedout')

      def test_revoke_api_token(self, ast):

@@ -67,25 +67,25 @@ 

              # Check that the milestones have their empty fields

              self.assertIn(

              '''<div id="milestones">

-               <div class="row p-t-1 milestone" id="milestone_1">

-                 <div class="col-sm-4 p-r-0">

-                   <input type="text" name="milestones"

-                     value="" size="3" class="form-control"/>

-                 </div>

-                 <div class="col-sm-4 p-r-0">

-                   <input type="text" name="milestone_date_1"

-                     value="" class="form-control"/>

-                 </div>

-                 <div class="col-sm-2 p-r-0" >

-                     <span class="fa fa-long-arrow-up milestone_order_up"

-                         data-stone="1"></span>

-                     <span class="fa fa-long-arrow-down milestone_order_bottom"

-                         data-stone="1"></span>

-                 </div>

-                 <div class="col-sm-1 p-r-0" >

-                     <input type="checkbox" name="active_milestone_1" />

-                 </div>

-               </div>''', output.get_data(as_text=True))

+       <div class="row p-t-1 milestone" id="milestone_1">

+         <div class="col-sm-4 p-r-0">

+           <input type="text" name="milestones"

+             value="" size="3" class="form-control"/>

+         </div>

+         <div class="col-sm-4 p-r-0">

+           <input type="text" name="milestone_date_1"

+             value="" class="form-control"/>

+         </div>

+         <div class="col-sm-2 p-r-0" >

+             <span class="fa fa-long-arrow-up milestone_order_up"

+                 data-stone="1"></span>

+             <span class="fa fa-long-arrow-down milestone_order_bottom"

+                 data-stone="1"></span>

+         </div>

+         <div class="col-sm-1 p-r-0" >

+             <input type="checkbox" name="active_milestone_1" />

+         </div>

+       </div>''', output.get_data(as_text=True))

  

      @patch('pagure.decorators.admin_session_timedout',

             MagicMock(return_value=False))