NEWS: Welcome to my new homepage! <3

post.c - poet - A terminal-based blogging interface

poet

A terminal-based blogging interface
git clone git://192.168.2.2/poet
Log | Files | Refs | README

post.c (7694B)


      1 #include <stdlib.h>
      2 #include <string.h>
      3 #include <stdbool.h>
      4 #include <inttypes.h>
      5 #include <libpq-fe.h>
      6 
      7 #include "util.h"
      8 #include "post.h"
      9 
     10 void post_init(post_t *post) {
     11   post->title = NULL;
     12   post->summary= NULL;
     13   post->content= NULL;
     14   post->date = NULL;
     15   post->is_public = NULL;
     16 }
     17 
     18 void post_free(post_t *post) {
     19   if (post->title != NULL) {
     20     free(post->title);
     21   }
     22   if (post->summary != NULL) {
     23     free(post->summary);
     24   }
     25   if (post->content != NULL) {
     26     free(post->content);
     27   }
     28   if (post->date != NULL) {
     29     free(post->date);
     30   }
     31   if (post->is_public != NULL) {
     32     free(post->is_public);
     33   }
     34 }
     35 
     36 void post_result_free(post_result_t *post_result) {
     37   if (post_result->result != NULL) {
     38     for (int i = 0; i < post_result->len; i++) {
     39       post_t *post = &post_result->result[i];
     40       post_free(post);
     41     }
     42     free(post_result->result);
     43   }
     44 }
     45 
     46 bool post_changed(post_t *post, post_t *changes) {
     47   if (changes->title != NULL && strcmp(post->title, changes->title) != 0) {
     48     return true;
     49   }
     50   if (changes->summary != NULL && strcmp(post->summary, changes->summary) != 0) {
     51     return true;
     52   }
     53   if (changes->content != NULL && strcmp(post->content, changes->content) != 0) {
     54     return true;
     55   }
     56   if (changes->date != NULL && strcmp(post->date, changes->date) != 0) {
     57     return true;
     58   }
     59   if (post->is_public != NULL && *post->is_public != *changes->is_public) {
     60     return true;
     61   }
     62   return false;
     63 }
     64 
     65 post_result_t *db_post_search(char *db, char *title) {
     66   PGconn *conn = PQconnectdb(db);
     67   if (PQstatus(conn) != CONNECTION_OK) {
     68     printf("error: %s\n", PQerrorMessage(conn));
     69     PQfinish(conn);
     70     return NULL;
     71   }
     72   char *query = "SELECT id, title, summary, created_at, is_public FROM posts WHERE lower(title) LIKE lower($1) ORDER BY created_at DESC;";
     73   char id_param[10];
     74   snprintf(id_param, 10, "%%%s%%", title);
     75   const char *values[1] = { id_param };
     76   PGresult *result = PQexecParams(conn, query, 1, NULL, values, NULL, NULL, 0);
     77   ExecStatusType status = PQresultStatus(result);
     78   if (status != PGRES_TUPLES_OK) {
     79     printf("error: %s\n", PQerrorMessage(conn));
     80     PQclear(result);
     81     PQfinish(conn);
     82     return NULL;
     83   }
     84   int rows = PQntuples(result);
     85   int cols = PQnfields(result);
     86   if (rows > 0) {
     87     post_result_t *post_result = calloc(1, sizeof(post_result_t));
     88     for (int i = 0; i < rows; i++) {
     89       post_result->result = realloc(post_result->result, sizeof(post_t) * (post_result->len + 1));
     90       post_t *post = &post_result->result[post_result->len];
     91       post_init(post);
     92       post_result->len++;
     93       for (int j = 0; j < cols; j++) {
     94         char *value = PQgetvalue(result, i, j);
     95         int value_len = strlen(value);
     96         if (j == 0) {
     97           int id = strtoimax(value, NULL, 10);
     98           post->id = id;
     99         }
    100         if (j == 1) {
    101           post->title = malloc(sizeof(char) * (value_len + 1));
    102           memcpy(post->title, value, value_len);
    103           post->title[value_len] = '\0';
    104         }
    105         if (j == 2) {
    106           post->summary = malloc(sizeof(char) * (value_len + 1));
    107           memcpy(post->summary, value, value_len);
    108           post->summary[value_len] = '\0';
    109         }
    110         if (j == 3) {
    111           post->date = malloc(sizeof(char) * (value_len + 1));
    112           memcpy(post->date, value, value_len);
    113           post->date[value_len] = '\0';
    114         }
    115         if (j == 4) {
    116           if (strcmp(value, "t") == 0) {
    117             post->is_public = malloc(sizeof(bool));
    118             *post->is_public = true;
    119           }
    120           else {
    121             post->is_public = malloc(sizeof(bool));
    122             *post->is_public = false;
    123           }
    124         }
    125       }
    126     }
    127     PQclear(result);
    128     PQfinish(conn);
    129     return post_result;
    130   }
    131   PQclear(result);
    132   PQfinish(conn);
    133   return NULL;
    134 }
    135 
    136 post_t *db_post_get(char *db, int id) {
    137   PGconn *conn = PQconnectdb(db);
    138   if (PQstatus(conn) != CONNECTION_OK) {
    139     printf("error: %s\n", PQerrorMessage(conn));
    140     PQfinish(conn);
    141     return NULL;
    142   }
    143   char *query = "SELECT title, summary, content, created_at, is_public FROM posts WHERE id = $1;";
    144   char id_param[10];
    145   snprintf(id_param, 10, "%d", id);
    146   const char *values[1] = { id_param };
    147   PGresult *result = PQexecParams(conn, query, 1, NULL, values, NULL, NULL, 0);
    148   ExecStatusType status = PQresultStatus(result);
    149   if (status != PGRES_TUPLES_OK) {
    150     printf("error: %s\n", PQerrorMessage(conn));
    151     PQclear(result);
    152     PQfinish(conn);
    153     return NULL;
    154   }
    155   int rows = PQntuples(result);
    156   int cols = PQnfields(result);
    157   if (rows > 0) {
    158     post_t *post = calloc(1, sizeof(post_t));
    159     post->id = id;
    160     for (int j = 0; j < cols; j++) {
    161       char *value = PQgetvalue(result, 0, j);
    162       int value_len = strlen(value);
    163       if (j == 0) {
    164         post->title = malloc(sizeof(char) * (value_len + 1));
    165         memcpy(post->title, value, value_len);
    166         post->title[value_len] = '\0';
    167       }
    168       if (j == 1) {
    169         post->summary = malloc(sizeof(char) * (value_len + 1));
    170         memcpy(post->summary, value, value_len);
    171         post->summary[value_len] = '\0';
    172       }
    173       if (j == 2) {
    174         post->content = malloc(sizeof(char) * (value_len + 1));
    175         memcpy(post->content, value, value_len);
    176         post->content[value_len] = '\0';
    177       }
    178       if (j == 3) {
    179         post->date = malloc(sizeof(char) * (value_len + 1));
    180         memcpy(post->date, value, value_len);
    181         post->date[value_len] = '\0';
    182       }
    183       if (j == 4) {
    184         if (strcmp(value, "t") == 0) {
    185           post->is_public = malloc(sizeof(bool));
    186           *post->is_public = true;
    187         }
    188         else {
    189           post->is_public = malloc(sizeof(bool));
    190           *post->is_public = false;
    191         }
    192       }
    193     }
    194     PQclear(result);
    195     PQfinish(conn);
    196     return post;
    197   }
    198   PQclear(result);
    199   PQfinish(conn);
    200   return NULL;
    201 }
    202 
    203 bool db_post_update(char *db, int id, post_t *post, post_t *changes) {
    204   PGconn *conn = PQconnectdb(db);
    205   if (PQstatus(conn) != CONNECTION_OK) {
    206     printf("error: %s\n", PQerrorMessage(conn));
    207     PQfinish(conn);
    208     return false;
    209   }
    210   char *query = NULL;
    211   const char *params[10];
    212   int count = 0;
    213   str_append(&query, "UPDATE posts SET");
    214   if (changes->title != NULL && strcmp(post->title, changes->title) != 0) {
    215     if (count > 0) {
    216       str_append(&query, ",");
    217     }
    218     str_appendf(&query, " title = $%d", count + 1);
    219     params[count] = changes->title;
    220     count++;
    221   }
    222   if (changes->summary != NULL && strcmp(post->summary, changes->summary) != 0) {
    223     if (count > 0) {
    224       str_append(&query, ",");
    225     }
    226     str_appendf(&query, " summary = $%d", count + 1);
    227     params[count] = changes->summary;
    228     count++;
    229   }
    230   if (changes->content != NULL && strcmp(post->content, changes->content) != 0) {
    231     if (count > 0) {
    232       str_appendf(&query, ",");
    233     }
    234     str_appendf(&query, " content = $%d", count + 1);
    235     params[count] = changes->content;
    236     count++;
    237   }
    238   if (post->is_public != NULL && *post->is_public != *changes->is_public) {
    239     if (count > 0) {
    240       str_appendf(&query, ",");
    241     }
    242     str_appendf(&query, " is_public = $%d", count + 1);
    243     params[count] = *changes->is_public ? "true" : "false";
    244     count++;
    245   }
    246   str_appendf(&query, " WHERE id = $%d", count + 1);
    247   char id_param[10];
    248   snprintf(id_param, 10, "%d", id);
    249   params[count] = id_param;
    250   count++;
    251   PGresult *result = PQexecParams(conn, query, count, NULL, params, NULL, NULL, 0);
    252   free(query);
    253   ExecStatusType status = PQresultStatus(result);
    254   if (status != PGRES_COMMAND_OK) {
    255     printf("error: %s\n", PQerrorMessage(conn));
    256     PQclear(result);
    257     PQfinish(conn);
    258     return false;
    259   }
    260   PQclear(result);
    261   PQfinish(conn);
    262   return true;
    263 }