Skip to:
Content

BuddyPress.org

Changeset 548


Ignore:
Timestamp:
11/17/2008 10:54:11 AM (16 years ago)
Author:
apeatling
Message:

Updated and fixed group invites and group invite email notifications.
Added screen notifications of group invites.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/bp-friends.php

    r527 r548  
    267267**************************************************************************/
    268268
     269function friends_check_user_has_friends( $user_id = false ) {
     270    if ( !$user_id )
     271        $user_id = $bp['current_userid'];
     272       
     273    $friend_count = get_usermeta( $user_id, 'total_friend_count');
     274       
     275    if ( $friend_count == '' )
     276        return false;
     277   
     278    if ( !(int)$friend_count )
     279        return false;
     280   
     281    return true;
     282}
     283
    269284function friends_get_friendships( $user_id = false, $friendship_ids = false, $pag_num = 5, $pag_page = 1, $get_requests = false, $count = false ) {
    270285    global $bp;
     
    322337    }
    323338
     339function friends_get_friends_invite_list( $user_id = false, $group_id ) {
     340    global $bp;
     341   
     342    if ( !$user_id )
     343        $user_id = $bp['loggedin_userid'];
     344   
     345    $friend_ids = BP_Friends_Friendship::get_friend_ids( $user_id );
     346
     347    for ( $i = 0; $i < count($friend_ids); $i++ ) {
     348        if ( groups_check_user_has_invite( $friend_ids[$i], $group_id ) || groups_is_user_member( $friend_ids[$i], $group_id ) )
     349            continue;
     350           
     351        $display_name = bp_fetch_user_fullname($friend_ids[$i], false);
     352       
     353        if ( $display_name != ' ' ) {
     354            $friends[] = array(
     355                'id' => $friend_ids[$i],
     356                'full_name' => $display_name
     357            );
     358        }
     359    }
     360   
     361    if ( $friends && is_array($friends) )
     362        usort($friends, 'friends_sort_by_name');
     363
     364    if ( !$friends )
     365        return false;
     366
     367    return $friends;
     368   
     369}
     370
     371function friends_count_invitable_friends( $user_id, $group_id ) {
     372    return BP_Friends_Friendship::get_invitable_friend_count( $user_id, $group_id );
     373}
    324374
    325375function friends_get_friend_ids_for_user( $user_id ) {
  • trunk/bp-friends/bp-friends-classes.php

    r469 r548  
    238238        global $wpdb, $bp;
    239239       
    240         $sql = $wpdb->prepare( "SELECT friend_user_id, initiator_user_id FROM " . $bp['friends']['table_name'] . " WHERE (friend_user_id = %d || initiator_user_id = %d) && is_confirmed = 1", $user_id, $user_id );
    241         $results = $wpdb->get_results($sql);
     240        $results = $wpdb->get_results( $wpdb->prepare( "SELECT friend_user_id, initiator_user_id FROM " . $bp['friends']['table_name'] . " WHERE (friend_user_id = %d || initiator_user_id = %d) && is_confirmed = 1", $user_id, $user_id ) );
    242241       
    243242        for ( $i = 0; $i < count($results); $i++ ) {
     
    267266    }
    268267   
     268    function get_invitable_friend_count( $user_id, $group_id ) {
     269        global $wpdb, $bp;
     270
     271        $friend_ids = BP_Friends_Friendship::get_friend_ids( $user_id );
     272       
     273        $invitable_count = 0;
     274        for ( $i = 0; $i < count($friend_ids); $i++ ) {
     275           
     276            if ( BP_Groups_Member::check_is_member( (int)$friend_ids[$i], $group_id ) )
     277                continue;
     278           
     279            if ( BP_Groups_Member::check_has_invite( (int)$friend_ids[$i], $group_id )  )
     280                continue;
     281               
     282            $invitable_count++;
     283        }
     284
     285        return $invitable_count;
     286    }
     287   
    269288    function get_user_ids_for_friendship( $friendship_id ) {
    270289        global $wpdb, $bp;
  • trunk/bp-groups.php

    r545 r548  
    33
    44define ( 'BP_GROUPS_IS_INSTALLED', 1 );
    5 define ( 'BP_GROUPS_VERSION', '0.2.5' );
     5define ( 'BP_GROUPS_VERSION', '0.2.6' );
    66
    77include_once( 'bp-groups/bp-groups-classes.php' );
     
    5858            is_confirmed tinyint(1) NOT NULL DEFAULT '0',
    5959            is_banned tinyint(1) NOT NULL DEFAULT '0',
     60            invite_sent tinyint(1) NOT NULL DEFAULT '0',
    6061            KEY group_id (group_id),
    6162            KEY is_admin (is_admin),
     
    309310    }
    310311   
     312    // Remove notifications
     313    bp_core_delete_notifications_for_user_by_type( $bp['loggedin_userid'], 'groups', 'group_invite' );
     314   
    311315    bp_catch_uri( 'groups/list-invites' ); 
    312316}
     
    458462   
    459463    if ( $is_single_group ) {
    460         if ( isset($bp['action_variables']) && $bp['action_variables'][1] == 'send' ) {
     464        if ( isset($bp['action_variables']) && $bp['action_variables'][0] == 'send' ) {
    461465            // Send the invites.
    462466            groups_send_invites($group_obj);
     
    865869            } else {
    866870                $user_fullname = bp_core_global_user_fullname( $requesting_user_id );
    867                 $user_url = bp_core_get_userurl( $requesting_user_id );
    868871                return '<a href="' . bp_group_permalink( $group, false ) . '/admin/membership-requests/" title="' . $user_fullname .' requests group membership">' . sprintf( __('%s requests membership for the group "%s"'), $user_fullname, $group->name ) . '</a>';
    869872            }   
     
    876879           
    877880            if ( (int)$total_items > 1 ) {
    878                 return '<a href="' . site_url() . '/' . MEMBERS_SLUG . '/' . $bp['groups']['slug'] . '" title="' . __( 'Groups', 'buddypress' ) . '">' . sprintf( __('%d accepted group membership requests'), (int)$total_items, $group->name ) . '</a>';     
     881                return '<a href="' . $bp['loggedin_domain'] . $bp['groups']['slug'] . '" title="' . __( 'Groups', 'buddypress' ) . '">' . sprintf( __('%d accepted group membership requests'), (int)$total_items, $group->name ) . '</a>';     
    879882            } else {
    880883                return '<a href="' . bp_group_permalink( $group, false ) . '/?new">' . sprintf( __('Membership for group "%s" accepted'), $group->name ) . '</a>';
     
    886889           
    887890            $group = new BP_Groups_Group( $group_id, false, false );
    888 
     891           
    889892            if ( (int)$total_items > 1 ) {
    890893                return '<a href="' . site_url() . '/' . MEMBERS_SLUG . '/' . $bp['groups']['slug'] . '" title="' . __( 'Groups', 'buddypress' ) . '">' . sprintf( __('%d rejected group membership requests'), (int)$total_items, $group->name ) . '</a>';     
     
    901904
    902905            if ( (int)$total_items > 1 ) {
    903                 return '<a href="' . site_url() . '/' . MEMBERS_SLUG . '/' . $bp['groups']['slug'] . '" title="' . __( 'Groups', 'buddypress' ) . '">' . sprintf( __('You were promoted to an admin in %d groups'), (int)$total_items ) . '</a>';       
     906                return '<a href="' . $bp['loggedin_domain'] . $bp['groups']['slug'] . '" title="' . __( 'Groups', 'buddypress' ) . '">' . sprintf( __('You were promoted to an admin in %d groups'), (int)$total_items ) . '</a>';     
    904907            } else {
    905908                return '<a href="' . bp_group_permalink( $group, false ) . '/?new">' . sprintf( __('You were promoted to an admin in the group %s'), $group->name ) . '</a>';
     
    913916
    914917            if ( (int)$total_items > 1 ) {
    915                 return '<a href="' . site_url() . '/' . MEMBERS_SLUG . '/' . $bp['groups']['slug'] . '" title="' . __( 'Groups', 'buddypress' ) . '">' . sprintf( __('You were promoted to a mod in %d groups'), (int)$total_items ) . '</a>';     
     918                return '<a href="' . $bp['loggedin_domain'] . $bp['groups']['slug'] . '" title="' . __( 'Groups', 'buddypress' ) . '">' . sprintf( __('You were promoted to a mod in %d groups'), (int)$total_items ) . '</a>';     
    916919            } else {
    917920                return '<a href="' . bp_group_permalink( $group, false ) . '/?new">' . sprintf( __('You were promoted to a mod in the group %s'), $group->name ) . '</a>';
     921            }   
     922        break;
     923       
     924        case 'group_invite':
     925            $group_id = $item_id;
     926
     927            $group = new BP_Groups_Group( $group_id, false, false );
     928            $user_url = bp_core_get_userurl( $user_id );
     929           
     930            if ( (int)$total_items > 1 ) {
     931                return '<a href="' . $bp['loggedin_domain'] . $bp['groups']['slug'] . '/invites" title="' . __( 'Group Invites', 'buddypress' ) . '">' . sprintf( __('You have %d new group invitations'), (int)$total_items ) . '</a>';       
     932            } else {
     933                return '<a href="' . $bp['loggedin_domain'] . $bp['groups']['slug'] . '/invites" title="' . __( 'Group Invites', 'buddypress' ) . '">' . sprintf( __('You have an invitation to the group: %s'), $group->name ) . '</a>';
    918934            }   
    919935        break;
     
    12421258
    12431259
    1244 function groups_get_invites_for_group( $group_id ) {
    1245     return BP_Groups_Group::get_invites( $group_id );
    1246 }
    1247 
    1248 
    1249 function groups_get_invites_for_user( $user_id = false ) {
     1260function groups_get_invites_for_group( $user_id, $group_id ) {
     1261    return BP_Groups_Group::get_invites( $user_id, $group_id );
     1262}
     1263
     1264function groups_check_user_has_invite( $user_id, $group_id ) {
     1265    BP_Groups_Member::check_has_invite( $user_id, $group_id );
     1266}
     1267
     1268function groups_get_invites_for_user( $user_id = false, $group_id = false ) {
    12501269    global $bp;
    12511270   
     
    12531272        $user_id = $bp['loggedin_userid'];
    12541273   
    1255     return BP_Groups_Member::get_invites($user_id);
     1274    return BP_Groups_Member::get_invites( $user_id, $group_id );
    12561275}
    12571276
     
    12611280   
    12621281    // Send friend invites.
    1263     $invited_users = groups_get_invites_for_group( $group_obj->id );
    1264    
    1265     for ( $i = 0; $i < count( $invited_users); $i++ ) {
    1266         $user_id = $invited_users[$i];
    1267 
    1268         // Send the email
    1269 
    1270         $invited_user = new BP_Core_User( $user_id );
    1271         $inviter_name = bp_core_get_userlink( $bp['loggedin_userid'], true, false, true );
    1272        
    1273         $message = "You have been invited to join the group '" . $group_obj->name . "' by " . $inviter_name . '.';
    1274         $message .= "\n\n";
    1275         $message .= "View the group: " . $invited_user->user_url . $bp['groups']['slug'] . "/" . $group_obj->slug . "\n";
    1276         $message .= "Accept the invite: " . $invited_user->user_url . $bp['groups']['slug'] . "/invites/accept/" . $group_obj->id . "\n";
    1277         $message .= "Reject the invite: " . $invited_user->user_url . $bp['groups']['slug'] . "/invites/reject/" . $group_obj->id . "\n";
    1278 
    1279         wp_mail( $invited_user->email, __("New Group Invitation:", 'buddypress') . $group_obj->name, $message, "From: noreply@" . $_SERVER[ 'HTTP_HOST' ]  );
    1280     }
    1281 
     1282    $invited_users = groups_get_invites_for_group( $bp['loggedin_userid'], $group_obj->id );
     1283
     1284    for ( $i = 0; $i < count( $invited_users ); $i++ ) {
     1285        $member = new BP_Groups_Member( $invited_users[$i], $group_obj->id );
     1286        $member->invite_sent = 1;
     1287        $member->save();
     1288    }
     1289   
     1290    groups_notification_group_invites( $group_obj->id, $invited_users, $bp['loggedin_userid'] );
     1291   
    12821292    do_action( 'groups_send_invites', $group_obj->id, $invited_users );
    12831293}
  • trunk/bp-groups/bp-groups-classes.php

    r540 r548  
    283283    }
    284284
    285     function get_invites( $group_id ) {
    286         global $wpdb, $bp;
    287         return $wpdb->get_col( $wpdb->prepare( "SELECT user_id FROM " . $bp['groups']['table_name_members'] . " WHERE group_id = %d and is_confirmed = 0", $group_id ) );
     285    function get_invites( $user_id, $group_id ) {
     286        global $wpdb, $bp;
     287        return $wpdb->get_results( $wpdb->prepare( "SELECT user_id FROM " . $bp['groups']['table_name_members'] . " WHERE group_id = %d and is_confirmed = 0 AND inviter_id = %d", $group_id, $user_id ), ARRAY_A );
    288288    }
    289289   
     
    465465    var $is_confirmed;
    466466    var $comments;
     467    var $invite_sent;
    467468   
    468469    var $user;
     
    508509            $this->is_confirmed = $member->is_confirmed;
    509510            $this->comments = $member->comments;
     511            $this->invite_sent = $member->invite_sent;
    510512           
    511513            $this->user = new BP_Core_User( $this->user_id );
     
    517519       
    518520        if ( $this->id ) {
    519             $sql = $wpdb->prepare( "UPDATE " . $bp['groups']['table_name_members'] . " SET inviter_id = %d, is_admin = %d, is_mod = %d, is_banned = %d, user_title = %s, date_modified = FROM_UNIXTIME(%d), is_confirmed = %d, comments = %s WHERE id = %d", $this->inviter_id, $this->is_admin, $this->is_mod, $this->is_banned, $this->user_title, $this->date_modified, $this->is_confirmed, $this->comments, $this->id );
     521            $sql = $wpdb->prepare( "UPDATE " . $bp['groups']['table_name_members'] . " SET inviter_id = %d, is_admin = %d, is_mod = %d, is_banned = %d, user_title = %s, date_modified = FROM_UNIXTIME(%d), is_confirmed = %d, comments = %s, invite_sent = %d WHERE id = %d", $this->inviter_id, $this->is_admin, $this->is_mod, $this->is_banned, $this->user_title, $this->date_modified, $this->is_confirmed, $this->comments, $this->invite_sent, $this->id );
    520522        } else {
    521             $sql = $wpdb->prepare( "INSERT INTO " . $bp['groups']['table_name_members'] . " ( user_id, group_id, inviter_id, is_admin, is_mod, is_banned, user_title, date_modified, is_confirmed, comments ) VALUES ( %d, %d, %d, %d, %d, %d, %s, FROM_UNIXTIME(%d), %d, %s )", $this->user_id, $this->group_id, $this->inviter_id, $this->is_admin, $this->is_mod, $this->is_banned, $this->user_title, $this->date_modified, $this->is_confirmed, $this->comments );
     523            $sql = $wpdb->prepare( "INSERT INTO " . $bp['groups']['table_name_members'] . " ( user_id, group_id, inviter_id, is_admin, is_mod, is_banned, user_title, date_modified, is_confirmed, comments, invite_sent ) VALUES ( %d, %d, %d, %d, %d, %d, %s, FROM_UNIXTIME(%d), %d, %s, %d )", $this->user_id, $this->group_id, $this->inviter_id, $this->is_admin, $this->is_mod, $this->is_banned, $this->user_title, $this->date_modified, $this->is_confirmed, $this->comments, $this->invite_sent );
    522524        }
    523525
     
    623625            return $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT count(group_id) FROM " . $bp['groups']['table_name_members'] . " WHERE user_id = %d AND inviter_id = 0 AND is_banned = 0", $user_id ) );           
    624626        } else {
    625             return $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT count(m.group_id) FROM " . $bp['groups']['table_name_members'] . " m, " . $bp['groups']['table_name'] . " g WHERE m.group_id = g.id AND g.status != 'hidden' AND m.user_id = %d AND m.inviter_id = 0 m.is_banned = 0", $user_id ) );           
     627            return $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT count(m.group_id) FROM " . $bp['groups']['table_name_members'] . " m, " . $bp['groups']['table_name'] . " g WHERE m.group_id = g.id AND g.status != 'hidden' AND m.user_id = %d AND m.inviter_id = 0 AND m.is_banned = 0", $user_id ) );           
    626628        }
    627629    }
     
    630632        global $wpdb, $bp;
    631633       
    632         $group_ids = $wpdb->get_col( $wpdb->prepare( "SELECT group_id FROM " . $bp['groups']['table_name_members'] . " WHERE user_id = %d and is_confirmed = 0 AND inviter_id != 0", $user_id ) );
     634        $group_ids = $wpdb->get_col( $wpdb->prepare( "SELECT group_id FROM " . $bp['groups']['table_name_members'] . " WHERE user_id = %d and is_confirmed = 0 AND inviter_id != 0 AND invite_sent = 1", $user_id ) );
    633635       
    634636        for ( $i = 0; $i < count($group_ids); $i++ ) {
     
    639641    }
    640642   
     643    function check_has_invite( $user_id, $group_id ) {
     644        global $wpdb, $bp;
     645       
     646        return $wpdb->get_var( $wpdb->prepare( "SELECT id FROM " . $bp['groups']['table_name_members'] . " WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND inviter_id != 0 AND invite_sent = 1", $user_id, $group_id ) );     
     647    }
     648   
    641649    function check_is_admin( $user_id, $group_id ) {
    642650        global $wpdb, $bp;
     
    666674        global $wpdb, $bp;
    667675       
    668         return $wpdb->query( $wpdb->prepare( "SELECT id FROM " . $bp['groups']['table_name_members'] . " WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND is_banned = 0", $user_id, $group_id ) );
     676        return $wpdb->query( $wpdb->prepare( "SELECT id FROM " . $bp['groups']['table_name_members'] . " WHERE user_id = %d AND group_id = %d AND is_confirmed = 0 AND is_banned = 0 AND inviter_id = 0", $user_id, $group_id ) ); 
    669677    }
    670678   
  • trunk/bp-groups/bp-groups-notifications.php

    r542 r548  
    8686
    8787function groups_notification_new_membership_request( $requesting_user_id, $admin_id, $group_id, $membership_id ) {
    88     global $bp, $current_user;
     88    global $bp;
    8989
    9090    bp_core_add_notification( $requesting_user_id, $admin_id, 'groups', 'new_membership_request', $group_id );
     
    127127
    128128function groups_notification_membership_request_completed( $requesting_user_id, $group_id, $accepted = true ) {
    129     global $bp, $current_user;
     129    global $bp;
    130130   
    131131    // Post a screen notification first.
     
    176176
    177177function groups_notification_promoted_member( $user_id, $group_id ) {
    178     global $bp, $current_user;
     178    global $bp;
    179179
    180180    if ( groups_is_user_admin( $user_id, $group_id ) ) {
     
    218218add_action( 'bp_groups_promoted_member', 'groups_notification_promoted_member', 10, 2 );
    219219
     220function groups_notification_group_invites( $group_id, $invited_user_ids, $inviter_user_id ) {
     221    global $bp;
     222   
     223    $inviter_ud = get_userdata($inviter_user_id);
     224    $inviter_name = bp_core_get_userlink( $inviter_user_id, true, false, true );
     225    $inviter_link = site_url() . '/' . MEMBERS_SLUG . '/' . $inviter_ud->user_login;
     226   
     227    $group = new BP_Groups_Group( $group_id, false, false );
     228    $group_link = bp_group_permalink( $group, false );
     229    $invites_link = $inviter_link . '/' . $bp['groups']['slug'] . '/invites';
     230       
     231    for ( $i = 0; $i < count( $invited_user_ids ); $i++ ) {
     232        $invited_user_id = $invited_user_ids[$i];
     233
     234        // Post a screen notification first.
     235        bp_core_add_notification( $group_id, $invited_user_id, 'groups', 'group_invite' );
     236
     237        if ( get_usermeta( $invited_user_id, 'notification_group_invitation' ) == 'no' ) continue;
     238
     239        $invited_ud = get_userdata($invited_user_id);
     240        $settings_link = site_url() . '/' . MEMBERS_SLUG . '/' . $ud->user_login . '/settings/notifications';
     241       
     242        // Set up and send the message
     243        $to = $invited_ud->user_email;
     244
     245        $subject = sprintf( __( 'You have an invitation to the group: "%s"', 'buddypress' ), stripslashes($group->name) );
     246
     247        $message = sprintf( __(
     248'One of your friends %s has invited you to the group: "%s".
     249
     250To view your group invites visit: %s
     251To view the group visit: %s
     252To view %s\'s profile visit: %s
     253
     254---------------------
     255', 'buddypress' ), $inviter_name, stripslashes($group->name), $invites_link, $group_link, $inviter_name, $inviter_link );
     256
     257        $message .= sprintf( __( 'To disable these notifications please log in and go to: %s', 'buddypress' ), $settings_link );
     258
     259        // Send it
     260        wp_mail( $to, $subject, $message );
     261    }
     262}
     263
    220264?>
  • trunk/bp-groups/bp-groups-templatetags.php

    r545 r548  
    795795<?php
    796796}
    797 function bp_group_list_friends() {
     797function bp_group_list_invite_friends() {
    798798    global $bp, $group_obj, $invites;
    799799   
    800     if ( bp_exists('friends') ) {
    801         $friends = friends_get_friends_list( $bp['loggedin_userid'] ); 
    802         $invites = groups_get_invites_for_group($group_obj->id);
    803 ?>
    804         <div id="invite-list">
    805             <ul>
    806                 <?php for ( $i = 0; $i < count( $friends ); $i++ ) {
    807                     if ( in_array( $friends[$i]['id'], $invites ) ) {
    808                         $checked = ' checked="checked"';
    809                     } else {
    810                         $checked = '';
    811                     } ?>
     800    if ( !function_exists('friends_install') )
     801        return false;
     802
     803        $friends = friends_get_friends_invite_list( $bp['loggedin_userid'], $group_obj->id );
     804
     805        if ( $friends ) {
     806            $invites = groups_get_invites_for_group( $bp['loggedin_userid'], $group_obj->id );
     807
     808    ?>
     809            <div id="invite-list">
     810                <ul>
     811                    <?php
     812                        for ( $i = 0; $i < count( $friends ); $i++ ) {
     813                            if ( $invites ) {
     814                                if ( in_array( $friends[$i]['id'], $invites ) ) {
     815                                    $checked = ' checked="checked"';
     816                                } else {
     817                                    $checked = '';
     818                                }
     819                            }
     820                    ?>
    812821                   
    813                 <li><input<?php echo $checked ?> type="checkbox" name="friends[]" id="f-<?php echo $friends[$i]['id'] ?>" value="<?php echo $friends[$i]['id'] ?>" /> <?php echo $friends[$i]['full_name']; ?></li>
    814                 <?php } ?>
    815             </ul>
    816         </div>
    817 <?php
    818     }
     822                    <li><input<?php echo $checked ?> type="checkbox" name="friends[]" id="f-<?php echo $friends[$i]['id'] ?>" value="<?php echo $friends[$i]['id'] ?>" /> <?php echo $friends[$i]['full_name']; ?></li>
     823                    <?php } ?>
     824                </ul>
     825            </div>
     826    <?php
     827        } else {
     828            _e( 'No friends to invite.', 'buddypress' );
     829        }
    819830}
    820831
     
    838849   
    839850    echo $bp['loggedin_domain'] . $bp['groups']['slug'] . '/invites/reject/' . $groups_template->group->id;
     851}
     852
     853function bp_has_friends_to_invite() {
     854    global $groups_template, $bp;
     855   
     856    if ( !function_exists('friends_install') )
     857        return false;
     858   
     859    if ( !friends_check_user_has_friends( $bp['loggedin_userid'] ) || !friends_count_invitable_friends( $bp['loggedin_userid'], $groups_template->group->id ) )
     860        return false;
     861   
     862    return true;
    840863}
    841864
     
    860883    <div class="left-menu">
    861884        <h4>Select Friends <img id="ajax-loader" src="<?php echo $bp['groups']['image_base'] ?>/ajax-loader.gif" height="7" alt="Loading" style="display: none;" /></h4>
    862         <?php bp_group_list_friends() ?>
     885        <?php bp_group_list_invite_friends() ?>
    863886        <?php if ( function_exists('wp_nonce_field') )
    864887            wp_nonce_field( 'invite_user' );
Note: See TracChangeset for help on using the changeset viewer.