瀏覽代碼

Add notify base and tests.

Cixo Develop 4 月之前
父節點
當前提交
a76dbf46ec
共有 6 個文件被更改,包括 339 次插入10 次删除
  1. 46 10
      sources/fetch.php
  2. 224 0
      sources/notification.php
  3. 17 0
      sources/notifier.php
  4. 23 0
      sources/subject.php
  5. 0 0
      tests/01-fetch.php
  6. 29 0
      tests/02-notify.php

+ 46 - 10
sources/fetch.php

@@ -21,7 +21,7 @@ use \curl_exec as curl_exec;
 use \curl_error as curl_error;
 use \curl_errno as curl_errno;
 
-require('response.php');
+require_once('response.php');
 
 /**
  * This class is responsible for downloading data from the server. It uses 
@@ -126,21 +126,51 @@ class fetch {
     }
 
     /**
-     * That add new header to the request. Name of the header must be full 
+     * That add new header for the request. Name of the header must be full
      * featured header name, like 'Cache-Control'. It also had been validated
      * and when name had been blacklisted, it raise RuntimeException. It also
      * raise RuntimeException when name has any white chars. Content had been 
      * validating, and it could not have new lines. Name and content would be
-     * trimed before processing.
+     * trimed before processing. Header could not already exists.
      * 
      * Blacklisted headers:
      * Content-Type, Content-Length
      * 
+     * @throws RuntimeException When header already exists.
+     * @throws RuntimeException When header is blacklisted.
+     * @throws RuntimeException When header contain blocked chars.
+     * 
      * @param string $name Name of the header.
      * @param string $content Content of the header.
      * @return fetch Self to chain processing.
      */
     public function add_header(string $name, string $content): object {
+        if (array_key_exists(trim($name), $this->headers)) {
+            throw new RuntimeExcetion('"'.$name.'" header already exists.');
+        }
+
+        return $this->set_header($name, $content);
+    }
+
+    /**
+     * That set header for the request. Name of the header must be full
+     * featured header name, like 'Cache-Control'. It also had been validated
+     * and when name had been blacklisted, it raise RuntimeException. It also
+     * raise RuntimeException when name has any white chars. Content had been 
+     * validating, and it could not have new lines. Name and content would be
+     * trimed before processing.
+     * 
+     * Blacklisted headers:
+     * Content-Type, Content-Length.
+     * 
+     * @throws RuntimeException When header is blacklisted.
+     * @throws RuntimeException When header contain blocked chars.
+     * 
+     * @param string $name Name of the header.
+     * @param string $content Content of the header.
+     * @return fetch Self to chain processing.
+     */
+    public function set_header(string $name, string $content): object {
         $name = trim($name);
         $content = trim($content);
 
@@ -150,8 +180,7 @@ class fetch {
             );
         }
 
-        $check_content = strpos($content, ' ') !== false;
-        $check_content = $check_content || strpos($content, "\r") !== false;
+        $check_content = strpos($content, "\r") !== false;
         $check_content = $check_content || strpos($content, "\n") !== false;
 
         if ($check_content) {
@@ -168,9 +197,7 @@ class fetch {
             throw new RuntimeException('Content-Lenght header is automatic.');
         }
 
-        $header = $name.': '.$content;
-        array_push($this->headers, $header);
-        
+        $this->headers[$name] = $name.': '.$content;
         return $this;
     }
 
@@ -195,7 +222,16 @@ class fetch {
         $this->method = $name;
         return $this;
     }
-    
+  
+    /** 
+     * This return list of all headers for the request.
+     * 
+     * @return array List of the all headers.
+     */
+    private function get_headers(): array {
+        return array_values($this->headers);
+    }
+
     /**
      * That function make request to the server, from fetch config, which
      * had been config previously. It return response in parsed form, as 
@@ -205,7 +241,7 @@ class fetch {
      * @return response Response from the server.
      */
     public function request(): response {
-        $headers = $this->headers;
+        $headers = $this->get_headers();
         $request = curl_init($this->url);
 
         curl_setopt($request, CURLOPT_RETURNTRANSFER, true);

+ 224 - 0
sources/notification.php

@@ -0,0 +1,224 @@
+<?php
+
+namespace phpnotify;
+
+require_once('fetch.php');
+
+class notification {
+    private array $tags;
+    private array $actions;
+    private fetch $request;
+
+    public function __construct(string $location, string $content) {
+        $this->tags = array();
+        $this->actions = array();
+
+        $this->request = new fetch($location);
+        $this->request->set_method('POST');
+        $this->request->send_raw($content, 'text/plain');
+    }
+
+    public function set_title(string $title): object {
+        $this->request->add_header('Title', $title);
+        return $this;
+    }
+
+    public function set_priority(int $priority): object {
+        if ($priority < 1 || $priority > 5) {
+            throw new TypeError('Priority must be between 1 and 5.');
+        }
+
+        $this->request->add_header('Priority', strval($priority));
+        return $this;
+    }
+
+    public function add_tag(string $tag): object {
+        $tag = trim($tag);
+
+        if (strpos($tag, ' ') !== false) {
+            throw new TypeError('Tags could not contain white chars.');
+        }
+
+        if (strpos($tag, ',') !== false) {
+            throw new TypeError('Tags could not contain ",".');
+        }
+
+        array_push($this->tags, $tag);
+        return $this;
+    }
+
+    private function get_tags(): string {
+        return join(',', $this->tags);
+    }
+
+    public function set_markdown(): object {
+        $this->request->add_header('Markdown', 'yes');
+        return $this;
+    }
+
+    public function delivery_time(string $when): object {
+        $this->request->add_header('At', $when);
+        return $this;
+    }
+
+    public function set_email(string $email): object {
+        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
+            throw new TypeError('Email "'.$email.'" is invalid.');
+        }
+
+        $this->request->add_header('Email', $email);
+        return $this;
+    }
+
+    public function click_url(string $url): object {
+        if (!filter_var($url, FILTER_VALIDATE_URL)) {
+            throw new TypeError('"'.$url.'" is not valid URL.');
+        }
+
+        $this->request->add_header('Action', $url);
+        return $this;
+    }
+
+    public function attach_url(string $url): object {
+        if (!filter_var($url, FILTER_VALIDATE_URL)) {
+            throw new TypeError('"'.$url.'" is not valid URL.');
+        }
+
+        $this->request->add_header('Attach', $url);
+        return $this;
+    }
+
+    public function icon_url(string $url): object {
+        if (!filter_var($url, FILTER_VALIDATE_URL)) {
+            throw new TypeError('"'.$url.'" is not valid URL.');
+        }
+
+        $this->request->add_header('Icon', $url);
+        return $this;
+    }
+
+    public function call(string|true $phone_number): object {
+        if ($phone_number === true) {
+            $this->request->add_header('Call', 'yes');
+            return $this;
+        }
+
+        $check = str_replace(' ', '', $phone_number);
+        
+        if ($check[0] === '+') {
+            $check = substr($check, 1);
+        }
+
+        if (!is_numeric($phone_number)) {
+            throw new TypeError('"'.$phone_number.'" is invalid number.');
+        }
+
+        $this->request->add_header('Call', $phone_number);
+        return $this;
+    }
+
+    public function save_as(string $filename): object {
+        if (basename($filename) !== $filename) {
+            throw new TypeError('"'.$filename.'" is invalid filename.');
+        }
+
+        $this->request->add_header('Filename', $filename);
+        return $this;
+    }
+
+    public function login(string $nick, string $password): object {
+        $decoded = $nick.':'.$password;
+        $encoded = base64_encode($decoded);
+        $param = 'Basic '.$encoded;
+
+        $this->request->add_header('Authorization', $param);
+        return $this;
+    }
+
+    public function token(string $token): object {
+        $token = trim($token);
+        $param = 'Bearer '.$token;
+
+        $this->request->add_header('Authorization', $param);
+        return $this;
+    }
+
+    public function disable_firebase(): object {
+        $this->request->add_header('Firebase', 'no');
+        return $this;
+    }
+
+    public function disable_cache(): object {
+        $this->request->add_header('Cache', 'no');
+        return $this;
+    }
+
+    public function set_poll_id(string $id): object {
+        $this->request->add_header('Poll-ID', $id);
+        return $this;
+    }
+
+    public function enable_unified_push(): object {
+        $this->request->add_header('UnifiedPush', 'yes');
+        return $this;
+    }
+
+    public function add_action(
+        string $action, 
+        string $label, 
+        ?array $param = null
+    ): object {
+        $separator = ', ';
+        $content = $action.$separator.$label;
+
+        if ($param === null) {
+            array_push($this->actions, $content);
+            return $this;
+        }
+
+        foreach ($param as $key => $value) {
+            $content .= $separator;
+            $content .= $key.'='.$value;
+        }
+            
+        array_push($this->actions, $content);
+        return $this;
+    }
+
+    private function get_actions(): string {
+        return join('; ', $this->actions);
+    }
+
+    public function send(bool $throws = false): bool {
+        $this->request->set_header('Actions', $this->get_actions());
+        $this->request->set_header('Tags', $this->get_tags());
+        
+        try {
+            $result = $this->request->request()->receive_array();
+
+            if (array_key_exists('id', $result)) {
+                return true;
+            }
+
+            if (count($result) === 0) {
+                throw new RuntimeException('Can not fetch. General error.');
+            }
+        
+            if (array_key_exists('error', $result)) {
+                $error = (
+                    'Can not publish: "'
+                    .$result['error']
+                    .'"'
+                );
+
+                throw new RuntimeException($error);
+            }
+        } catch (Exception $error) {
+            if ($throws) {
+                throw $error;
+            }
+
+            return false;
+        }
+    }
+}

+ 17 - 0
sources/notifier.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace phpnotify;
+
+require_once('subject.php');
+
+class notifier {
+    private string $url;
+
+    public function __construct(string $url) {
+        $this->url = $url;
+    }
+
+    public function subscribe(string $subject): subject {
+        return new subject($this->url, $subject);
+    }
+}

+ 23 - 0
sources/subject.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace phpnotify;
+
+require_once('notification.php');
+
+class subject {
+    private string $url;
+    private string $subject;
+
+    public function __construct(string $url, string $subject) {
+        $this->url = $url;
+        $this->subject = $subject;
+    }
+
+    private function get_subject_url(): string {
+        return $this->url.'/'.$this->subject;
+    }
+
+    public function publish(string $content): notification {
+        return new notification($this->get_subject_url(), $content);
+    }
+}

+ 0 - 0
tests/fetch.php → tests/01-fetch.php


+ 29 - 0
tests/02-notify.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace phpnotify;
+
+require_once('../sources/notifier.php');
+require_once('../sources/subject.php');
+require_once('../sources/notification.php');
+
+function get_line(string $name): string {
+    $content = file_get_contents($name);
+    $content = str_replace('\r', '', $content);
+    $content = str_replace('\n', '', $content);
+
+    return $content;
+}
+
+
+$TOKEN = get_line('.token');
+$URL = get_line('.url');
+$SUBJECT = get_line('.subject');
+
+$notifier = new notifier('https://ntfy.cixoelectronic.pl');
+$subject = $notifier->subscribe('test');
+
+$subject
+->publish('Sample content')
+->set_title('Title of')
+->token($TOKEN)
+->send(true);