From 66f3b2b1290eb78940e4f1674e1de0e3f77f161a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andrej=20Rama=C5=A1euski?= <andrej@x2.cz>
Date: Thu, 26 May 2022 00:19:13 +0200
Subject: [PATCH] Podpora chobotnice

---
 .dockerignore                       |  6 +++
 .gitignore                          |  2 +
 .gitlab-ci.yml                      | 12 +++---
 Dockerfile                          | 16 +++++++-
 VERSION                             |  1 +
 lib/RVVote/Chobotnice.pm            | 63 +++++++++++++++++++++++++++++
 lib/RVVote/Controller/RV.pm         | 17 +++++---
 lib/RVVote/{GraphAPI.pm => IAPI.pm} | 33 +++++++--------
 r_v_vote.conf                       | 12 ++++--
 templates/rv_form.html.ep           | 10 ++---
 10 files changed, 133 insertions(+), 39 deletions(-)
 create mode 100644 .dockerignore
 create mode 100644 .gitignore
 create mode 100644 VERSION
 create mode 100644 lib/RVVote/Chobotnice.pm
 rename lib/RVVote/{GraphAPI.pm => IAPI.pm} (51%)

diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..b90fc28
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,6 @@
+**
+!lib
+!public
+!script
+!templates
+!r_v_vote.conf
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0f160fe
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+_work
+docker-compose.yaml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9b09b14..6e89260 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,11 +1,10 @@
-image: docker:19.03.1
+image: docker:20.10.9
 
 variables:
   DOCKER_TLS_CERTDIR: "/certs"
-  IMAGE_TAG: $CI_REGISTRY_IMAGE:latest
 
 services:
-  - docker:19.03.1-dind
+  - docker:20.10.9-dind
 
 before_script:
   - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
@@ -13,5 +12,8 @@ before_script:
 build:
   stage: build
   script:
-    - docker build -t $IMAGE_TAG .
-    - docker push $IMAGE_TAG
+    - VERSION=`cat VERSION`
+    - docker pull $CI_REGISTRY_IMAGE:latest || true
+    - docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:$VERSION --tag $CI_REGISTRY_IMAGE:latest .
+    - docker push $CI_REGISTRY_IMAGE:$VERSION
+    - docker push $CI_REGISTRY_IMAGE:latest
diff --git a/Dockerfile b/Dockerfile
index 16ec601..ce5d963 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,21 @@
-FROM docker-registry.pirati.cz/ramaseuski/docker-mojolicious 
+FROM alpine:latest
+
+RUN apk update && apk add \
+    wget \
+    make \
+    gcc \
+    perl-dev \
+    perl-mojolicious \
+    perl-json \
+    perl-yaml \
+    perl-io-socket-ssl \
+  	perl-app-cpanminus
+
+RUN cpanm GraphQL::Client
 
 ADD . /opt/rvvote
 
+USER daemon
 EXPOSE 3000
 WORKDIR /opt/rvvote
 CMD ./script/rvvote daemon
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..9084fa2
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+1.1.0
diff --git a/lib/RVVote/Chobotnice.pm b/lib/RVVote/Chobotnice.pm
new file mode 100644
index 0000000..d4026c2
--- /dev/null
+++ b/lib/RVVote/Chobotnice.pm
@@ -0,0 +1,63 @@
+package RVVote::Chobotnice;
+
+use strict;
+use warnings;
+use utf8;
+use GraphQL::Client;
+use YAML;
+
+our $VERSION = '0.01';
+
+sub new {
+    my $classname = shift;
+    my $url  = shift;
+    my $self = {};
+
+    $self->{client} = GraphQL::Client->new(url => $url);
+
+    bless ($self, $classname);
+    return $self;
+}
+
+sub client {
+    my $self = shift;
+    return $self->{client};
+}
+
+sub get_group_members {
+    my $self     = shift;
+    my $group_id = shift;
+
+    my $query = qq[
+        query MyQuery {
+            group(id: "$group_id") {
+                memberships {
+                    person {
+                        username
+                        displayName
+                        officialLastName
+                    }
+                }
+            }
+        }
+    ];
+
+    my $res = $self->client->execute($query);
+    return undef if $res->{errors};
+    return undef if ! $res->{data};
+
+    my @members = ();
+
+    MEMBER:
+    foreach my $member ( @{ $res->{data}{group}{memberships} } ) {
+        push @members, {
+            fullname => $member->{person}{displayName},
+            user_id  => lc($member->{person}{username}),
+            lastname => $member->{person}{officialLastName},
+        };
+    }
+
+    return sort { $a->{lastname} cmp $b->{lastname} } @members;
+}
+
+1;
diff --git a/lib/RVVote/Controller/RV.pm b/lib/RVVote/Controller/RV.pm
index c1def3a..95022c0 100644
--- a/lib/RVVote/Controller/RV.pm
+++ b/lib/RVVote/Controller/RV.pm
@@ -1,6 +1,7 @@
 package RVVote::Controller::RV;
 use Mojo::Base 'Mojolicious::Controller';
-use RVVote::GraphAPI;
+use RVVote::IAPI;
+use RVVote::Chobotnice;
 use MIME::Base64 qw(decode_base64url);
 use JSON;
 
@@ -11,7 +12,7 @@ sub index {
 
 sub members {
     my $c = shift;
-   
+
     my @members = ();
 
     if ($c->param('election')) {
@@ -25,11 +26,17 @@ sub members {
                 }
             } @{ $election }
         };
-    } 
+    }
 
     if ( ! scalar @members ) {
-        my $gapi = RVVote::GraphAPI->new($c->config->{graph_api}{url});
-        @members = $gapi->get_group_members($c->config->{graph_api}{rv_gid});
+        if ( $ENV{USERS_BACKEND} eq 'iapi' ) {
+            my $iapi = RVVote::IAPI->new($c->config->{iapi}{url});
+            @members = $iapi->get_group_members($c->config->{iapi}{rv_gid});
+        }
+        elsif ( $ENV{USERS_BACKEND} eq 'chobotnice' ) {
+            my $chobotnice = RVVote::Chobotnice->new($c->config->{chobotnice}{url});
+            @members = $chobotnice->get_group_members($c->config->{chobotnice}{rv_gid});
+        }
     }
 
     $c->render( json => \@members );
diff --git a/lib/RVVote/GraphAPI.pm b/lib/RVVote/IAPI.pm
similarity index 51%
rename from lib/RVVote/GraphAPI.pm
rename to lib/RVVote/IAPI.pm
index 7c3a95f..5ec4ef1 100644
--- a/lib/RVVote/GraphAPI.pm
+++ b/lib/RVVote/IAPI.pm
@@ -1,4 +1,4 @@
-package RVVote::GraphAPI;
+package RVVote::IAPI;
 
 use strict;
 use warnings;
@@ -28,32 +28,27 @@ sub get_group_members {
     my $self     = shift;
     my $group_id = shift;
 
-    my $res = $self->ua->get( join '/', (
-        $self->{base_url},
-        $group_id,
-        'members'
-    ))->result();
+    my $res = $self->ua->get(
+        sprintf($self->{base_url}, $group_id)
+    )->result();
 
-    return undef if ! $res->is_success;    
+    return undef if ! $res->is_success;
     return undef if ! ref $res->json eq 'ARRAY';
 
     my @members = ();
 
     MEMBER:
     foreach my $member ( @{ $res->json } ) {
-        my $res2 = $self->ua->get( join '/', (
-            $self->{base_url},
-            'user',
-            $member->{username_clean},
-        ))->result();
-        next MEMBER if ! $res2->is_success;    
-        next MEMBER if ! ref $res2->json eq 'ARRAY';
-
-        $member = $res2->json;
-        (undef, $member->{lastname}) = split /\./, $member->{username_clean};
-        push @members, $member;
+        my (undef, $lastname) = split /\s+/, $member->{displayname};
+        push @members, {
+            fullname => $member->{displayname},
+            user_id  => $member->{username},
+            lastname => $lastname,
+        };
     }
 
     return sort { $a->{lastname} cmp $b->{lastname} } @members;
 
-};
+}
+
+1;
diff --git a/r_v_vote.conf b/r_v_vote.conf
index 06fca89..d264665 100644
--- a/r_v_vote.conf
+++ b/r_v_vote.conf
@@ -1,7 +1,11 @@
 {
     secrets       => ['ac605478557638569200e0e5333891c04929159a'],
-    graph_api => {
-        url     => 'https://graph.pirati.cz', 
-        rv_gid  => 'deadbeef-babe-f002-000000000404', 
-    }
+    iapi => {
+        url    => 'https://iapi.pirati.cz/v1/groups/%d/members',
+        rv_gid => 404,
+    },
+    chobotnice => {
+        url    => 'https://chobotnice.pirati.cz/graphql/',
+        rv_gid => 'R3JvdXBUeXBlOjUzMg==',
+    },
 }
diff --git a/templates/rv_form.html.ep b/templates/rv_form.html.ep
index 5a326b5..374b599 100644
--- a/templates/rv_form.html.ep
+++ b/templates/rv_form.html.ep
@@ -32,15 +32,15 @@ function evaluate() {
     var a = $('form').serializeArray();
     $.each(a, function() {
         var id = this.name.split('_');
-        bills.push({ 
-            "id": id[1], 
-            "value": this.value, 
-            "voter": $('input[name='+this.name+']').attr('data-fullname'),
+        bills.push({
+            "id": id[1],
+            "value": this.value,
+            "voter": $('input[name="'+this.name+'"]').attr('data-fullname'),
         });
     });
 
     $.ajax({
-        url: '/api/calculate/',                 
+        url: '/api/calculate/',
         data: JSON.stringify(bills),
         contentType: 'application/json',
         type: "POST",
-- 
GitLab