[Patchew-devel] [PATCH] Make Patchew cli use rest api

Paolo Bonzini pbonzini at redhat.com
Mon Jun 25 12:13:50 UTC 2018


On 25/06/2018 14:06, Shubham Jain wrote:
> - Disabled CSRF authentication until OAuth authentication, since DRF leads to csrf error while handling sessionauthentication.
> - Added general rest_api function to make request to apis and get response.
> - Make project functions use the rest_api_do instead of api_do

Thanks.

CSRF cannot really be removed before we have some kind of token-based
authentication, either TokenAuthentication or OAUTH, so this part of the
project needs to be developed in a branch.  I still prefer not to delay
this part because it's really telling us if the REST API works or not.

Fam, how would you prefer to handle the branching?  We cannot change
patchew-cli until patchew.org has the REST API; and I would like to have
my "result" table patches before we branch, since they seem to be
stable, but before that we need to test migration on patchew.org (not
just next.patchew.org).  I can think of two strategies:

1) branch "next" now, then apply the "result" table patches to both
master and next

2) Shubham works into a branch that is neither master nor next, and we
apply his patches only after token-based authentication is done.

What do you prefer?

Thanks,

Paolo


> ---
>  api/rest.py |  9 +++++++-
>  patchew-cli | 69 +++++++++++++++++++++++++++++++++++++++++++++++--------------
>  2 files changed, 61 insertions(+), 17 deletions(-)
> 
> diff --git a/api/rest.py b/api/rest.py
> index 084dbbc..a584578 100644
> --- a/api/rest.py
> +++ b/api/rest.py
> @@ -25,6 +25,12 @@ from rest_framework.response import Response
>  import rest_framework
>  from mbox import addr_db_to_rest, MboxMessage
>  from rest_framework.parsers import JSONParser, BaseParser
> +from rest_framework.authentication import SessionAuthentication
> +
> +class CsrfExemptSessionAuthentication(SessionAuthentication):
> +
> +    def enforce_csrf(self, request):
> +        return  # To not perform the csrf check previously happening
>  
>  SEARCH_PARAM = 'q'
>  
> @@ -140,7 +146,8 @@ class ProjectsViewSet(viewsets.ModelViewSet):
>      queryset = Project.objects.all().order_by('id')
>      serializer_class = ProjectSerializer
>      permission_classes = (PatchewPermission,)
> -
> +    authentication_classes = (CsrfExemptSessionAuthentication, )
> +    
>      @action(methods=['post'], detail=True, permission_classes=[ImportPermission])
>      def update_project_head(self, request, pk=None):
>          """
> diff --git a/patchew-cli b/patchew-cli
> index 174d1e6..cd5b3fa 100755
> --- a/patchew-cli
> +++ b/patchew-cli
> @@ -61,7 +61,7 @@ class SubCommand(object):
>      help = ""
>      want_argv = False # Whether the command accepts extra arguments
>  
> -    def api_do(self, cmd, **data):
> +    def api_do(self, cmd, **data):  
>          """Do server api call"""
>          logging.debug("API call '%s':" % cmd)
>          logging.debug("data:\n%s" % data)
> @@ -92,6 +92,39 @@ class SubCommand(object):
>              r = None
>          return r
>  
> +    def rest_api_do(self, url_cmd, request_method='get', content_type=None, **data):
> +        cmd = url_cmd
> +        logging.debug("API call '%s':" % url_cmd)
> +        logging.debug("data:\n%s" % data)
> +        cookie = http.cookiejar.MozillaCookieJar(COOKIE_FILENAME)
> +        try:
> +            cookie.load()
> +        except IOError:
> +            pass
> +        except http.cookiejar.LoadError:
> +            print("Error while loading cookie", COOKIE_FILENAME)
> +            pass
> +        handler = urllib.request.HTTPCookieProcessor(cookie)
> +        opener = urllib.request.build_opener(handler)
> +        url = self.base_url + '/api/v1/' + url_cmd + '/'
> +        if data:
> +            post_data = json.dumps(data)
> +        else:
> +            post_data = ""
> +        req = urllib.request.Request(url, data=bytes(post_data, encoding="utf-8"))
> +        if content_type is not None:
> +            req.add_header('Content-Type', content_type)
> +        req.get_method = lambda: request_method.upper()
> +        resp = opener.open(req)
> +        cookie.save(ignore_discard=True, ignore_expires=True)
> +        respdata = resp.read()
> +        logging.debug("Server response:\n%s" % (respdata or "<empty>"))
> +        if respdata:
> +            r = json.loads(respdata.decode("utf-8"))
> +        else:
> +            r = None
> +        return r
> +
>      def do(self, args, argv):
>          """Do command"""
>          print("Not implemented")
> @@ -221,11 +254,11 @@ class ProjectCommand(SubCommand):
>          parser.add_argument("--verbose", "-v", action="store_true",
>                              help="Show details about projects")
>          args = parser.parse_args(argv)
> -        r = self.api_do("get-projects")
> +        r = self.rest_api_do(url_cmd="projects", request_method='get')
>          if args.raw:
>              print(json.dumps(r, indent=2, separators=",:"))
>              return 0
> -        for p in r:
> +        for p in r['results']:
>              print(p["name"])
>              if args.verbose:
>                  for k, v in p.items():
> @@ -239,8 +272,8 @@ class ProjectCommand(SubCommand):
>          parser.add_argument("name", nargs="+",
>                              help="The name of project to show info")
>          args = parser.parse_args(argv)
> -        r = self.api_do("get-projects")
> -        for p in r:
> +        r = self.rest_api_do(url_cmd="projects", request_method='get')
> +        for p in r['results']:
>              if not p["name"] in args.name:
>                  continue
>              if len(args.name) > 1:
> @@ -263,12 +296,15 @@ class ProjectCommand(SubCommand):
>          parser.add_argument("--desc", "-d", default="",
>                              help="Project short discription")
>          args = parser.parse_args(argv)
> -        self.api_do("add-project",
> -                    name=args.name,
> -                    mailing_list=args.mailing_list,
> -                    url=args.url,
> -                    git=args.git,
> -                    description=args.desc)
> +
> +        self.rest_api_do(url_cmd="projects",
> +                         request_method='post',
> +                         content_type='application/json',
> +                         name=args.name,
> +                         mailing_list=args.mailing_list,
> +                         url=args.url,
> +                         git=args.git,
> +                         description=args.desc)
>  
>      def update_one_project(self, wd, project):
>          logging.info("Updating project '%s'", project["name"])
> @@ -320,16 +356,17 @@ class ProjectCommand(SubCommand):
>              except Exception as e:
>                  logging.warn("Failed to push the new head to patchew mirror: %s",
>                               str(e))
> -        self.api_do("update-project-head", project=project["name"],
> -                                           old_head=old_head,
> -                                           new_head=new_head,
> -                                           message_ids=msgids)
> +        url = "project/" + project.id + "/update_project_head/"
> +        self.rest_api_do("project-head",old_head=old_head,
> +                                        new_head=new_head,
> +                                        message_ids=msgids)
>  
>      def update_project(self, argv):
>          parser = argparse.ArgumentParser()
>          parser.add_argument("--name", "-n", help="Name of the project")
>          args = parser.parse_args(argv)
> -        projects = self.api_do("get-projects", name=args.name)
> +        projects = self.rest_api_do("projects")
> +        projects = [p for p in projects['results'] if p['name'] == args.name]
>          wd = tempfile.mkdtemp()
>          logging.debug("TMPDIR: %s", wd)
>          try:
> 




More information about the Patchew-devel mailing list