!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache. PHP/8.1.30 

uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC
2025 x86_64
 

uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root)  

Safe-mode: OFF (not secure)

/home/picotech/domains/note.picotech.app/public_html/src/models/   drwxr-xr-x
Free 25.88 GB of 117.98 GB (21.93%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     Note.js (5.49 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
const { DataTypes } = require('sequelize');
const { sequelize } = require('../config/database');

const Note = sequelize.define('Note', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  meeting_id: {
    type: DataTypes.INTEGER,
    allowNull: false,
    references: {
      model: 'meetings',
      key: 'id',
    },
    onDelete: 'CASCADE',
  },
  user_id: {
    type: DataTypes.INTEGER,
    allowNull: false,
    references: {
      model: 'users',
      key: 'id',
    },
    onDelete: 'CASCADE',
  },
  title: {
    type: DataTypes.STRING(255),
    allowNull: true,
    defaultValue: 'Untitled Note',
  },
  content_blocks: {
    type: DataTypes.JSON,
    allowNull: false,
    defaultValue: [],
    validate: {
      isValidContentBlocks(value) {
        if (!Array.isArray(value)) {
          throw new Error('Content blocks must be an array');
        }
        for (const block of value) {
          if (!block.id || !block.type || typeof block.content !== 'string') {
            throw new Error('Each content block must have id, type, and content');
          }
          if (!['text', 'bullet', 'heading', 'action_item', 'ai_suggestion'].includes(block.type)) {
            throw new Error('Invalid content block type');
          }
        }
      },
    },
  },
  tags: {
    type: DataTypes.JSON,
    defaultValue: [],
    allowNull: true,
    validate: {
      isArray(value) {
        if (!Array.isArray(value)) {
          throw new Error('Tags must be an array');
        }
      },
    },
  },
  status: {
    type: DataTypes.ENUM('draft', 'active', 'completed', 'archived'),
    defaultValue: 'draft',
    allowNull: false,
  },
  priority: {
    type: DataTypes.ENUM('low', 'medium', 'high', 'urgent'),
    defaultValue: 'medium',
    allowNull: false,
  },
  color: {
    type: DataTypes.STRING(7),
    allowNull: true,
    validate: {
      is: /^#[0-9A-F]{6}$/i,
    },
  },
  is_pinned: {
    type: DataTypes.BOOLEAN,
    defaultValue: false,
  },
  word_count: {
    type: DataTypes.INTEGER,
    defaultValue: 0,
    allowNull: false,
  },
  last_edited_by: {
    type: DataTypes.INTEGER,
    allowNull: true,
    references: {
      model: 'users',
      key: 'id',
    },
  },
  version: {
    type: DataTypes.INTEGER,
    defaultValue: 1,
    allowNull: false,
  },
  parent_note_id: {
    type: DataTypes.INTEGER,
    allowNull: true,
    references: {
      model: 'notes',
      key: 'id',
    },
    comment: 'For note threading/replies',
  },
}, {
  tableName: 'notes',
  timestamps: true,
  indexes: [
    {
      fields: ['meeting_id'],
    },
    {
      fields: ['user_id'],
    },
    {
      fields: ['status'],
    },
    {
      fields: ['meeting_id', 'user_id'],
    },
    {
      fields: ['is_pinned'],
    },
    {
      fields: ['priority'],
    },
  ],
  hooks: {
    beforeSave: (note) => {
      // Calculate word count from content blocks
      if (note.content_blocks && Array.isArray(note.content_blocks)) {
        const totalWords = note.content_blocks.reduce((count, block) => {
          if (block.content && typeof block.content === 'string') {
            return count + block.content.trim().split(/\s+/).filter(word => word.length > 0).length;
          }
          return count;
        }, 0);
        note.word_count = totalWords;
      }
      
      // Increment version on update
      if (!note.isNewRecord) {
        note.version += 1;
      }
    },
  },
});

// Instance methods
Note.prototype.getPlainTextContent = function() {
  if (!this.content_blocks || !Array.isArray(this.content_blocks)) {
    return '';
  }
  
  return this.content_blocks
    .map(block => block.content || '')
    .join(' ')
    .replace(/<[^>]*>/g, '') // Remove HTML tags
    .trim();
};

Note.prototype.getActionItems = function() {
  if (!this.content_blocks || !Array.isArray(this.content_blocks)) {
    return [];
  }
  
  return this.content_blocks.filter(block => block.type === 'action_item');
};

Note.prototype.hasTag = function(tag) {
  return this.tags && Array.isArray(this.tags) && this.tags.includes(tag);
};

Note.prototype.addTag = function(tag) {
  if (!this.tags) {
    this.tags = [];
  }
  if (!this.hasTag(tag)) {
    this.tags.push(tag);
  }
  return this;
};

Note.prototype.removeTag = function(tag) {
  if (this.tags && Array.isArray(this.tags)) {
    this.tags = this.tags.filter(t => t !== tag);
  }
  return this;
};

// Class methods
Note.findByMeeting = function(meetingId, options = {}) {
  return this.findAll({
    where: {
      meeting_id: meetingId,
      ...options.where,
    },
    order: options.order || [['created_at', 'ASC']],
    ...options,
  });
};

Note.findByUser = function(userId, options = {}) {
  return this.findAll({
    where: {
      user_id: userId,
      ...options.where,
    },
    order: options.order || [['updated_at', 'DESC']],
    ...options,
  });
};

Note.findPinnedByUser = function(userId) {
  return this.findAll({
    where: {
      user_id: userId,
      is_pinned: true,
    },
    order: [['updated_at', 'DESC']],
  });
};

Note.searchByContent = function(userId, searchTerm, options = {}) {
  const { Op } = sequelize.Sequelize;
  
  return this.findAll({
    where: {
      user_id: userId,
      [Op.or]: [
        {
          title: {
            [Op.like]: `%${searchTerm}%`,
          },
        },
        sequelize.literal(`JSON_SEARCH(content_blocks, 'all', '%${searchTerm}%') IS NOT NULL`),
      ],
      ...options.where,
    },
    order: options.order || [['updated_at', 'DESC']],
    limit: options.limit || 50,
  });
};

module.exports = Note;

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0058 ]--