<?php

/**

 * Plugin Name: WPMU Storage Quota Monitor

 * Plugin URI:  https://example.com/

 * Description: Emails the network administrator when a site in a Multisite network approaches its upload storage quota.

 * Version:     1.0

 * Author:      Your Name

 * Author URI:  https://example.com/

 * License:     GPL2

 */


// Exit if accessed directly.

if ( ! defined( 'ABSPATH' ) ) {

    exit;

}


class WPMU_Storage_Quota_Monitor {


    private $threshold_percentage = 80; // Email when usage reaches 80% of the quota

    private $email_interval_hours = 24; // Only send email once every 24 hours per site

    private $option_name_last_notified = 'wpmu_sqm_last_notified';


    public function __construct() {

        if ( is_multisite() ) {

            add_action( 'admin_init', array( $this, 'schedule_quota_check' ) );

            add_action( 'wpmu_storage_quota_check', array( $this, 'check_all_site_quotas' ) );

            add_action( 'admin_menu', array( $this, 'add_settings_page' ) );

            add_action( 'admin_init', array( $this, 'register_settings' ) );

        }

    }


    /**

     * Schedules the daily quota check.

     */

    public function schedule_quota_check() {

        if ( ! wp_next_scheduled( 'wpmu_storage_quota_check' ) ) {

            wp_schedule_event( time(), 'daily', 'wpmu_storage_quota_check' );

        }

    }


    /**

     * Unschedule the event on plugin deactivation.

     */

    public static function unschedule_quota_check_on_deactivation() {

        wp_clear_scheduled_hook( 'wpmu_storage_quota_check' );

    }


    /**

     * Checks the upload quota for all sites in the network.

     */

    public function check_all_site_quotas() {

        // Get the threshold percentage from settings, fallback to default.

        $this->threshold_percentage = get_site_option( 'wpmu_sqm_threshold_percentage', 80 );

        $this->email_interval_hours = get_site_option( 'wpmu_sqm_email_interval_hours', 24 );


        $sites = get_sites( array( 'fields' => 'ids', 'limit' => -1 ) );

        foreach ( $sites as $site_id ) {

            $this->check_single_site_quota( $site_id );

        }

    }


    /**

     * Checks the upload quota for a single site and sends an email if near limit.

     *

     * @param int $site_id The ID of the site to check.

     */

    private function check_single_site_quota( $site_id ) {

        switch_to_blog( $site_id );


        $quota_bytes = get_option( 'blog_upload_space' ); // Quota in MB, convert to bytes.

        if ( empty( $quota_bytes ) || $quota_bytes == 0 ) {

            restore_current_blog();

            return; // No quota set for this site, or quota is unlimited.

        }

        $quota_bytes *= MB_IN_BYTES; // Convert MB to bytes.


        $used_bytes = get_option( 'blog_upload_space_used' ); // Used space in MB, convert to bytes.

        $used_bytes *= MB_IN_BYTES; // Convert MB to bytes.


        if ( $quota_bytes <= 0 ) { // Ensure quota is positive to avoid division by zero.

            restore_current_blog();

            return;

        }


        $percentage_used = ( $used_bytes / $quota_bytes ) * 100;


        if ( $percentage_used >= $this->threshold_percentage ) {

            $this->send_quota_notification_email( $site_id, $used_bytes, $quota_bytes, $percentage_used );

        }


        restore_current_blog();

    }


    /**

     * Sends an email notification if the site is near its quota and not recently notified.

     *

     * @param int    $site_id         The ID of the site.

     * @param int    $used_bytes      The amount of storage used in bytes.

     * @param int    $quota_bytes     The total quota in bytes.

     * @param float  $percentage_used The percentage of quota used.

     */

    private function send_quota_notification_email( $site_id, $used_bytes, $quota_bytes, $percentage_used ) {

        $last_notified = get_site_option( $this->option_name_last_notified . '_' . $site_id );

        $current_time = time();


        // Check if enough time has passed since the last notification for this site.

        if ( $last_notified && ( $current_time - $last_notified ) < ( $this->email_interval_hours * HOUR_IN_SECONDS ) ) {

            return; // Too soon to send another email for this site.

        }


        $network_admin_email = get_site_option( 'admin_email' ); // Get the network admin email.

        if ( ! $network_admin_email ) {

            return; // No network admin email set.

        }


        $site_name = get_blog_details( $site_id )->blogname;

        $site_url  = get_blog_details( $site_id )->siteurl;


        $subject = sprintf( __( 'Storage Quota Alert for %s', 'wpmu-storage-quota-monitor' ), $site_name );


        $message = sprintf(

            __( "Hello Network Administrator,\n\n" .

                "The site '%1\$s' (%2\$s) is nearing its upload storage quota.\n\n" .

                "Current Usage: %3\$s MB (%.2f%% of quota)\n" .

                "Total Quota: %4\$s MB\n\n" .

                "Please consider increasing the site's upload space or advising the site administrator to reduce file usage.\n\n" .

                "This is an automated notification.",

                'wpmu-storage-quota-monitor' ),

            $site_name,

            $site_url,

            round( $used_bytes / MB_IN_BYTES, 2 ),

            $percentage_used,

            round( $quota_bytes / MB_IN_BYTES, 2 )

        );


        $headers = array( 'Content-Type: text/plain; charset=UTF-8' );


        // Send the email.

        if ( wp_mail( $network_admin_email, $subject, $message, $headers ) ) {

            // Update the last notified timestamp for this site.

            update_site_option( $this->option_name_last_notified . '_' . $site_id, $current_time );

        }

    }


    /**

     * Adds the settings page to the Network Admin menu.

     */

    public function add_settings_page() {

        add_submenu_page(

            'settings.php', // Parent slug for Network Settings.

            __( 'Storage Quota Monitor Settings', 'wpmu-storage-quota-monitor' ),

            __( 'Quota Monitor', 'wpmu-storage-quota-monitor' ),

            'manage_network_options', // Capability required to access.

            'wpmu-storage-quota-monitor-settings',

            array( $this, 'settings_page_content' )

        );

    }


    /**

     * Registers plugin settings.

     */

    public function register_settings() {

        add_action( 'network_admin_edit_wpmu_storage_quota_monitor_settings', array( $this, 'save_settings' ) );


        add_settings_section(

            'wpmu_sqm_general_settings',

            __( 'General Settings', 'wpmu-storage-quota-monitor' ),

            null,

            'wpmu-storage-quota-monitor-settings'

        );


        add_settings_field(

            'wpmu_sqm_threshold_percentage',

            __( 'Notification Threshold (%)', 'wpmu-storage-quota-monitor' ),

            array( $this, 'threshold_percentage_callback' ),

            'wpmu-storage-quota-monitor-settings',

            'wpmu_sqm_general_settings'

        );


        add_settings_field(

            'wpmu_sqm_email_interval_hours',

            __( 'Email Notification Interval (hours)', 'wpmu-storage-quota-monitor' ),

            array( $this, 'email_interval_hours_callback' ),

            'wpmu-storage-quota-monitor-settings',

            'wpmu_sqm_general_settings'

        );

    }


    /**

     * Callback for the threshold percentage setting field.

     */

    public function threshold_percentage_callback() {

        $threshold = get_site_option( 'wpmu_sqm_threshold_percentage', 80 );

        echo '<input type="number" name="wpmu_sqm_threshold_percentage" min="1" max="100" value="' . esc_attr( $threshold ) . '"/>';

        echo '<p class="description">' . __( 'Send an email notification when a site\'s upload space usage reaches this percentage of its quota.', 'wpmu-storage-quota-monitor' ) . '</p>';

    }


    /**

     * Callback for the email interval hours setting field.

     */

    public function email_interval_hours_callback() {

        $interval = get_site_option( 'wpmu_sqm_email_interval_hours', 24 );

        echo '<input type="number" name="wpmu_sqm_email_interval_hours" min="1" value="' . esc_attr( $interval ) . '"/>';

        echo '<p class="description">' . __( 'How often (in hours) to send email notifications for the same site if it remains above the threshold. Set to 0 for every check.', 'wpmu-storage-quota-monitor' ) . '</p>';

    }


    /**

     * Saves the plugin settings.

     */

    public function save_settings() {

        if ( ! current_user_can( 'manage_network_options' ) ) {

            wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpmu-storage-quota-monitor' ) );

        }


        check_admin_referer( 'wpmu-storage-quota-monitor-settings-options' ); // Verify nonce.


        $threshold = isset( $_POST['wpmu_sqm_threshold_percentage'] ) ? intval( $_POST['wpmu_sqm_threshold_percentage'] ) : 80;

        $interval = isset( $_POST['wpmu_sqm_email_interval_hours'] ) ? intval( $_POST['wpmu_sqm_email_interval_hours'] ) : 24;


        update_site_option( 'wpmu_sqm_threshold_percentage', max( 1, min( 100, $threshold ) ) );

        update_site_option( 'wpmu_sqm_email_interval_hours', max( 0, $interval ) );


        wp_redirect( add_query_arg( array( 'page' => 'wpmu-storage-quota-monitor-settings', 'updated' => 'true' ), network_admin_url( 'settings.php' ) ) );

        exit();

    }



    /**

     * Displays the settings page content.

     */

    public function settings_page_content() {

        ?>

        <div class="wrap">

            <h1><?php _e( 'WPMU Storage Quota Monitor Settings', 'wpmu-storage-quota-monitor' ); ?></h1>

            <form method="post" action="<?php echo esc_url( network_admin_url( 'edit.php?action=wpmu_storage_quota_monitor_settings' ) ); ?>">

                <?php

                settings_fields( 'wpmu-storage-quota-monitor-settings-options' ); // Nonce for the settings page.

                do_settings_sections( 'wpmu-storage-quota-monitor-settings' );

                submit_button();

                ?>

            </form>

        </div>

        <?php

    }

}


// Initialize the plugin.

$wpmu_storage_quota_monitor = new WPMU_Storage_Quota_Monitor();


// Register deactivation hook.

register_deactivation_hook( __FILE__, array( 'WPMU_Storage_Quota_Monitor', 'unschedule_quota_check_on_deactivation' ) );

Class of ’60s Speaker – Elaine Shi, Carnegie Mellon University – Computer Science

Class of '60s Speaker - Elaine Shi, Carnegie Mellon University

Computer Science Class of ’60s Events:

Elaine Shi is a professor with a joint appointment in CSD and ECE at Carnegie Mellon University. Her research interests include cryptography, security, mechanism design, algorithms, foundations of blockchains, and programming languages. She is a co-founder of Oblivious Labs, Inc. Her research on Oblivious RAM and differentially private algorithms have been adopted by SignalMeta, and Google.

She is a Sloan Fellow, Packard Fellow, ACM Fellow, and IACR Fellow, and her work has won numerous awards.

Thursday, May 01

4:15pm in Bronfman Auditorium (Wachenheim B11)

Secure Multi-Party Computation

Imagine that several hospitals want to collaborate on data analysis using their medical records. However, privacy regulations prevent them from directly sharing this sensitive information with one another. At first glance, this computational task might seem fundamentally at odds with the need for confidentiality — but this is where cryptography can work its magic. In this lecture, I will introduce some simple secure multi-party computation protocols that make this collaboration possible without compromising privacy.

Friday, May 02

2:35pm in Wege Auditorium (TCL 123)

How to access a large database without leaking your intentions

In contact discovery, you want to retrieve records corresponding to your friends from some server. However, you are privacy-aware and you would rather not disclose your contacts to the server.  In this talk, I will describe some simple algorithms called Oblivious RAM (ORAM)  that allow us to access a large database without disclosing our intentions. In particular, I will describe our work on Path ORAM which has been implemented/deployed by companies such as Signal and Meta.