<div dir="ltr">Paolo, also we need to write some tests. there are no tests for update-project-head and delete series that uses patches-cli<div>Thanks</div><div>Shubham</div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Jun 25, 2018 at 5:43 PM Paolo Bonzini <<a href="mailto:pbonzini@redhat.com" target="_blank">pbonzini@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 25/06/2018 14:06, Shubham Jain wrote:<br>
> - Disabled CSRF authentication until OAuth authentication, since DRF leads to csrf error while handling sessionauthentication.<br>
> - Added general rest_api function to make request to apis and get response.<br>
> - Make project functions use the rest_api_do instead of api_do<br>
<br>
Thanks.<br>
<br>
CSRF cannot really be removed before we have some kind of token-based<br>
authentication, either TokenAuthentication or OAUTH, so this part of the<br>
project needs to be developed in a branch.  I still prefer not to delay<br>
this part because it's really telling us if the REST API works or not.<br>
<br>
Fam, how would you prefer to handle the branching?  We cannot change<br>
patchew-cli until <a href="http://patchew.org" rel="noreferrer" target="_blank">patchew.org</a> has the REST API; and I would like to have<br>
my "result" table patches before we branch, since they seem to be<br>
stable, but before that we need to test migration on <a href="http://patchew.org" rel="noreferrer" target="_blank">patchew.org</a> (not<br>
just <a href="http://next.patchew.org" rel="noreferrer" target="_blank">next.patchew.org</a>).  I can think of two strategies:<br>
<br>
1) branch "next" now, then apply the "result" table patches to both<br>
master and next<br>
<br>
2) Shubham works into a branch that is neither master nor next, and we<br>
apply his patches only after token-based authentication is done.<br>
<br>
What do you prefer?<br>
<br>
Thanks,<br>
<br>
Paolo<br>
<br>
<br>
> ---<br>
>  api/rest.py |  9 +++++++-<br>
>  patchew-cli | 69 +++++++++++++++++++++++++++++++++++++++++++++++--------------<br>
>  2 files changed, 61 insertions(+), 17 deletions(-)<br>
> <br>
> diff --git a/api/rest.py b/api/rest.py<br>
> index 084dbbc..a584578 100644<br>
> --- a/api/rest.py<br>
> +++ b/api/rest.py<br>
> @@ -25,6 +25,12 @@ from rest_framework.response import Response<br>
>  import rest_framework<br>
>  from mbox import addr_db_to_rest, MboxMessage<br>
>  from rest_framework.parsers import JSONParser, BaseParser<br>
> +from rest_framework.authentication import SessionAuthentication<br>
> +<br>
> +class CsrfExemptSessionAuthentication(SessionAuthentication):<br>
> +<br>
> +    def enforce_csrf(self, request):<br>
> +        return  # To not perform the csrf check previously happening<br>
>  <br>
>  SEARCH_PARAM = 'q'<br>
>  <br>
> @@ -140,7 +146,8 @@ class ProjectsViewSet(viewsets.ModelViewSet):<br>
>      queryset = Project.objects.all().order_by('id')<br>
>      serializer_class = ProjectSerializer<br>
>      permission_classes = (PatchewPermission,)<br>
> -<br>
> +    authentication_classes = (CsrfExemptSessionAuthentication, )<br>
> +    <br>
>      @action(methods=['post'], detail=True, permission_classes=[ImportPermission])<br>
>      def update_project_head(self, request, pk=None):<br>
>          """<br>
> diff --git a/patchew-cli b/patchew-cli<br>
> index 174d1e6..cd5b3fa 100755<br>
> --- a/patchew-cli<br>
> +++ b/patchew-cli<br>
> @@ -61,7 +61,7 @@ class SubCommand(object):<br>
>      help = ""<br>
>      want_argv = False # Whether the command accepts extra arguments<br>
>  <br>
> -    def api_do(self, cmd, **data):<br>
> +    def api_do(self, cmd, **data):  <br>
>          """Do server api call"""<br>
>          logging.debug("API call '%s':" % cmd)<br>
>          logging.debug("data:\n%s" % data)<br>
> @@ -92,6 +92,39 @@ class SubCommand(object):<br>
>              r = None<br>
>          return r<br>
>  <br>
> +    def rest_api_do(self, url_cmd, request_method='get', content_type=None, **data):<br>
> +        cmd = url_cmd<br>
> +        logging.debug("API call '%s':" % url_cmd)<br>
> +        logging.debug("data:\n%s" % data)<br>
> +        cookie = http.cookiejar.MozillaCookieJar(COOKIE_FILENAME)<br>
> +        try:<br>
> +            cookie.load()<br>
> +        except IOError:<br>
> +            pass<br>
> +        except http.cookiejar.LoadError:<br>
> +            print("Error while loading cookie", COOKIE_FILENAME)<br>
> +            pass<br>
> +        handler = urllib.request.HTTPCookieProcessor(cookie)<br>
> +        opener = urllib.request.build_opener(handler)<br>
> +        url = self.base_url + '/api/v1/' + url_cmd + '/'<br>
> +        if data:<br>
> +            post_data = json.dumps(data)<br>
> +        else:<br>
> +            post_data = ""<br>
> +        req = urllib.request.Request(url, data=bytes(post_data, encoding="utf-8"))<br>
> +        if content_type is not None:<br>
> +            req.add_header('Content-Type', content_type)<br>
> +        req.get_method = lambda: request_method.upper()<br>
> +        resp = opener.open(req)<br>
> +        cookie.save(ignore_discard=True, ignore_expires=True)<br>
> +        respdata = resp.read()<br>
> +        logging.debug("Server response:\n%s" % (respdata or "<empty>"))<br>
> +        if respdata:<br>
> +            r = json.loads(respdata.decode("utf-8"))<br>
> +        else:<br>
> +            r = None<br>
> +        return r<br>
> +<br>
>      def do(self, args, argv):<br>
>          """Do command"""<br>
>          print("Not implemented")<br>
> @@ -221,11 +254,11 @@ class ProjectCommand(SubCommand):<br>
>          parser.add_argument("--verbose", "-v", action="store_true",<br>
>                              help="Show details about projects")<br>
>          args = parser.parse_args(argv)<br>
> -        r = self.api_do("get-projects")<br>
> +        r = self.rest_api_do(url_cmd="projects", request_method='get')<br>
>          if args.raw:<br>
>              print(json.dumps(r, indent=2, separators=",:"))<br>
>              return 0<br>
> -        for p in r:<br>
> +        for p in r['results']:<br>
>              print(p["name"])<br>
>              if args.verbose:<br>
>                  for k, v in p.items():<br>
> @@ -239,8 +272,8 @@ class ProjectCommand(SubCommand):<br>
>          parser.add_argument("name", nargs="+",<br>
>                              help="The name of project to show info")<br>
>          args = parser.parse_args(argv)<br>
> -        r = self.api_do("get-projects")<br>
> -        for p in r:<br>
> +        r = self.rest_api_do(url_cmd="projects", request_method='get')<br>
> +        for p in r['results']:<br>
>              if not p["name"] in <a href="http://args.name" rel="noreferrer" target="_blank">args.name</a>:<br>
>                  continue<br>
>              if len(<a href="http://args.name" rel="noreferrer" target="_blank">args.name</a>) > 1:<br>
> @@ -263,12 +296,15 @@ class ProjectCommand(SubCommand):<br>
>          parser.add_argument("--desc", "-d", default="",<br>
>                              help="Project short discription")<br>
>          args = parser.parse_args(argv)<br>
> -        self.api_do("add-project",<br>
> -                    name=<a href="http://args.name" rel="noreferrer" target="_blank">args.name</a>,<br>
> -                    mailing_list=args.mailing_list,<br>
> -                    url=args.url,<br>
> -                    git=args.git,<br>
> -                    description=args.desc)<br>
> +<br>
> +        self.rest_api_do(url_cmd="projects",<br>
> +                         request_method='post',<br>
> +                         content_type='application/json',<br>
> +                         name=<a href="http://args.name" rel="noreferrer" target="_blank">args.name</a>,<br>
> +                         mailing_list=args.mailing_list,<br>
> +                         url=args.url,<br>
> +                         git=args.git,<br>
> +                         description=args.desc)<br>
>  <br>
>      def update_one_project(self, wd, project):<br>
>          <a href="http://logging.info" rel="noreferrer" target="_blank">logging.info</a>("Updating project '%s'", project["name"])<br>
> @@ -320,16 +356,17 @@ class ProjectCommand(SubCommand):<br>
>              except Exception as e:<br>
>                  logging.warn("Failed to push the new head to patchew mirror: %s",<br>
>                               str(e))<br>
> -        self.api_do("update-project-head", project=project["name"],<br>
> -                                           old_head=old_head,<br>
> -                                           new_head=new_head,<br>
> -                                           message_ids=msgids)<br>
> +        url = "project/" + <a href="http://project.id" rel="noreferrer" target="_blank">project.id</a> + "/update_project_head/"<br>
> +        self.rest_api_do("project-head",old_head=old_head,<br>
> +                                        new_head=new_head,<br>
> +                                        message_ids=msgids)<br>
>  <br>
>      def update_project(self, argv):<br>
>          parser = argparse.ArgumentParser()<br>
>          parser.add_argument("--name", "-n", help="Name of the project")<br>
>          args = parser.parse_args(argv)<br>
> -        projects = self.api_do("get-projects", name=<a href="http://args.name" rel="noreferrer" target="_blank">args.name</a>)<br>
> +        projects = self.rest_api_do("projects")<br>
> +        projects = [p for p in projects['results'] if p['name'] == <a href="http://args.name" rel="noreferrer" target="_blank">args.name</a>]<br>
>          wd = tempfile.mkdtemp()<br>
>          logging.debug("TMPDIR: %s", wd)<br>
>          try:<br>
> <br>
<br>
</blockquote></div>